1 /*
2  * @brief DMA memory to memory transfer example
3  *
4  * @note
5  * Copyright(C) NXP Semiconductors, 2013
6  * All rights reserved.
7  *
8  * @par
9  * Software that is described herein is for illustrative purposes only
10  * which provides customers with programming information regarding the
11  * LPC products.  This software is supplied "AS IS" without any warranties of
12  * any kind, and NXP Semiconductors and its licensor disclaim any and
13  * all warranties, express or implied, including all implied warranties of
14  * merchantability, fitness for a particular purpose and non-infringement of
15  * intellectual property rights.  NXP Semiconductors assumes no responsibility
16  * or liability for the use of the software, conveys no license or rights under any
17  * patent, copyright, mask work right, or any other intellectual property rights in
18  * or to any products. NXP Semiconductors reserves the right to make changes
19  * in the software without notification. NXP Semiconductors also makes no
20  * representation or warranty that such application will be suitable for the
21  * specified use without further testing or modification.
22  *
23  * @par
24  * Permission to use, copy, modify, and distribute this software and its
25  * documentation is hereby granted, under NXP Semiconductors' and its
26  * licensor's relevant copyrights in the software, without fee, provided that it
27  * is used in conjunction with NXP Semiconductors microcontrollers.  This
28  * copyright, permission, and disclaimer notice must appear in all copies of
29  * this code.
30  */
31 
32 #include <stdlib.h>
33 #include <string.h>
34 #include "board.h"
35 #include "stopwatch.h"
36 
37 /*****************************************************************************
38  * Private types/enumerations/variables
39  ****************************************************************************/
40 
41 /* Number of memory operations to use for application */
42 #define NUMBER_TRANSFER_OPS     50000
43 
44 /* Size of the source and destination buffers in 32-bit words.
45    Allowable values  = 128, 256, 512, or 1024 */
46 #define SIZE_BUFFERS            (512)
47 
48 /* Source and destination buffers */
49 uint32_t src[SIZE_BUFFERS], dst[SIZE_BUFFERS];
50 
51 /* DMA completion flag */
52 static volatile bool dmaDone;
53 
54 /* Enable this define to test the data after memory transfers */
55 /* #define XFERTEST */
56 
57 /*****************************************************************************
58  * Public types/enumerations/variables
59  ****************************************************************************/
60 
61 /*****************************************************************************
62  * Private functions
63  ****************************************************************************/
64 
65 /* Populate source array with changing data, clear destination data */
modifyData(uint32_t * src,uint32_t * dst,int words)66 static void modifyData(uint32_t *src, uint32_t *dst, int words)
67 {
68 #if defined(XFERTEST)
69 	int i;
70 
71 	/* Put some data in the source buffer for test */
72 	for (i = 0; i < words; i++) {
73 		src[i] = src[i] + i + 1;
74 		dst[i] = 0;
75 	}
76 #endif
77 }
78 
79 /* Simple data verification */
verifyData(uint32_t * src,uint32_t * dst,int words)80 static void verifyData(uint32_t *src, uint32_t *dst, int words)
81 {
82 #if defined(XFERTEST)
83 	int i, errIdx = -1;
84 
85 	for (i = 0; ((i < words) && (errIdx == -1)); i++) {
86 		if (src[i] != dst[i]) {
87 			errIdx = i;
88 		}
89 	}
90 
91 	if (errIdx != -1) {
92 		Board_LED_Set(1, true);	/* LED 1 indicates a compare error */
93 		DEBUGOUT("Compare error on index %d\r\n", errIdx);
94 	}
95 #endif
96 }
97 
98 /*****************************************************************************
99  * Public functions
100  ****************************************************************************/
101 
102 /**
103  * @brief	DMA Interrupt Handler
104  * @return	None
105  */
DMA_IRQHandler(void)106 void DMA_IRQHandler(void)
107 {
108 	/* Error interrupt on channel 0? */
109 	if ((Chip_DMA_GetIntStatus(LPC_DMA) & DMA_INTSTAT_ACTIVEERRINT) != 0) {
110 		/* This shouldn't happen for this simple DMA example, so set the LED
111 		   to indicate an error occurred. This is the correct method to clear
112 		   an abort. */
113 		Chip_DMA_DisableChannel(LPC_DMA, DMA_CH0);
114 		while ((Chip_DMA_GetBusyChannels(LPC_DMA) & (1 << DMA_CH0)) != 0) {}
115 		Chip_DMA_AbortChannel(LPC_DMA, DMA_CH0);
116 		Chip_DMA_ClearErrorIntChannel(LPC_DMA, DMA_CH0);
117 		Chip_DMA_EnableChannel(LPC_DMA, DMA_CH0);
118 		Board_LED_Set(0, true);
119 	}
120 
121 	/* Clear DMA interrupt for the channel */
122 	Chip_DMA_ClearActiveIntAChannel(LPC_DMA, DMA_CH0);
123 
124 	dmaDone = true;
125 }
126 
127 /**
128  * @brief	Main program body
129  * @return	int
130  */
main(void)131 int main(void)
132 {
133 	DMA_CHDESC_T dmaDesc;
134 	int i;
135 	uint32_t startTime, ticks[3];
136 
137 	/* Setup SystemCoreClock and any needed board code */
138 	SystemCoreClockUpdate();
139 	Board_Init();
140 
141 	/* Initialize stopwatch */
142 	StopWatch_Init();
143 
144 	DEBUGOUT("Test transfer size is %d blocks @ %d bytes each\r\n",
145 			 NUMBER_TRANSFER_OPS, (SIZE_BUFFERS * 4));
146 	DEBUGOUT("Total test size = %d bytes\r\n",
147 			 (NUMBER_TRANSFER_OPS * SIZE_BUFFERS * 4));
148 
149 	/* Reset timer and perform a bunch memory to memory moves with memmove */
150 	DEBUGOUT("Starting memmove test\r\n");
151 	startTime = StopWatch_Start();
152 	for (i = 0; i < NUMBER_TRANSFER_OPS; i++) {
153 		modifyData(src, dst, SIZE_BUFFERS);
154 		memmove(dst, src, sizeof(src));
155 		verifyData(src, dst, SIZE_BUFFERS);
156 	}
157 	ticks[0] = StopWatch_Elapsed(startTime);
158 
159 	/* Reset timer and perform a bunch memory to memory moves with memcpy */
160 	DEBUGOUT("Starting memcpy test\r\n");
161 	startTime = StopWatch_Start();
162 	for (i = 0; i < NUMBER_TRANSFER_OPS; i++) {
163 		modifyData(src, dst, SIZE_BUFFERS);
164 		memcpy(dst, src, sizeof(src));
165 		verifyData(src, dst, SIZE_BUFFERS);
166 	}
167 	ticks[1] = StopWatch_Elapsed(startTime);
168 
169 	/* DMA initialization - enable DMA clocking and reset DMA if needed */
170 	Chip_DMA_Init(LPC_DMA);
171 
172 	/* Enable DMA controller and use driver provided DMA table for current descriptors */
173 	Chip_DMA_Enable(LPC_DMA);
174 	Chip_DMA_SetSRAMBase(LPC_DMA, DMA_ADDR(Chip_DMA_Table));
175 
176 	/* Setup channel 0 for the following configuration:
177 	   - High channel priority
178 	   - Interrupt A fires on descriptor completion */
179 	Chip_DMA_EnableChannel(LPC_DMA, DMA_CH0);
180 	Chip_DMA_EnableIntChannel(LPC_DMA, DMA_CH0);
181 	Chip_DMA_SetupChannelConfig(LPC_DMA, DMA_CH0,
182 								(DMA_CFG_HWTRIGEN | DMA_CFG_TRIGTYPE_EDGE | DMA_CFG_TRIGPOL_HIGH |
183 								 DMA_CFG_BURSTPOWER_128 | DMA_CFG_CHPRIORITY(0)));
184 
185 	/* DMA descriptor for memory to memory operation - note that addresses must
186 	   be the END address for src and destination, not the starting address.
187 	     DMA operations moves from end to start. */
188 	dmaDesc.source = DMA_ADDR(&src[SIZE_BUFFERS - 1]) + 3;
189 	dmaDesc.dest = DMA_ADDR(&dst[SIZE_BUFFERS - 1]) + 3;
190 	dmaDesc.next = DMA_ADDR(0);
191 
192 	/* Enable DMA interrupt */
193 	NVIC_EnableIRQ(DMA_IRQn);
194 
195 	/* Reset timer and perform a bunch memory to memory moves with DMA */
196 	DEBUGOUT("Starting DMA test\r\n");
197 	startTime = StopWatch_Start();
198 	for (i = 0; i < NUMBER_TRANSFER_OPS; i++) {
199 		dmaDone = false;
200 
201 		modifyData(src, dst, SIZE_BUFFERS);
202 
203 		/* Setup transfer descriptor and validate it */
204 		Chip_DMA_SetupTranChannel(LPC_DMA, DMA_CH0, &dmaDesc);
205 		Chip_DMA_SetValidChannel(LPC_DMA, DMA_CH0);
206 
207 		/* Setup data transfer and software trigger in same call */
208 		Chip_DMA_SetupChannelTransfer(LPC_DMA, DMA_CH0,
209 									  (DMA_XFERCFG_CFGVALID | DMA_XFERCFG_SETINTA | DMA_XFERCFG_SWTRIG |
210 									   DMA_XFERCFG_WIDTH_32 | DMA_XFERCFG_SRCINC_1 | DMA_XFERCFG_DSTINC_1 |
211 									   DMA_XFERCFG_XFERCOUNT(SIZE_BUFFERS)));
212 
213 		/* Wait for DMA completion */
214 		while (dmaDone == false) {
215 			Chip_PMU_SleepState(LPC_PMU);
216 		}
217 
218 		verifyData(src, dst, SIZE_BUFFERS);
219 	}
220 	ticks[2] = StopWatch_Elapsed(startTime);
221 	DEBUGOUT("Transfer time with memmove (mS) = %d\r\n", StopWatch_TicksToMs(ticks[0]));
222 	DEBUGOUT("Transfer time with memcpy (mS) = %d\r\n", StopWatch_TicksToMs(ticks[1]));
223 	DEBUGOUT("Transfer time with DMA (mS) = %d\r\n", StopWatch_TicksToMs(ticks[2]));
224 
225 	return 0;
226 }
227