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