| LPCOpen Platform v1.03 LPCOpen Platform for NXP LPC Microcontrollers

- Main Page
- Modules
- Data Structures
- Files
- Related Pages

- File List
- Globals

All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
app_sdmmc_meas.c
Go to the documentation of this file.
1 /*
2 * @brief SD/MMC benchmark example
3 *
4 * @note
5 * Copyright(C) NXP Semiconductors, 2012
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 <string.h>
33 #include "board.h"
34 #include "chip.h"
35
72 /*****************************************************************************
73 * Private types/enumerations/variables
74 ****************************************************************************/
75 /* Compiler specific attributes */
76 #if defined(__IAR_SYSTEMS_ICC__)
77 #define LOCATE_ATX(x) _Pragma(#x)
78 #define LOCATE_ATXX(x) LOCATE_ATX(location=x)
79 #define LOCATE_AT(x) LOCATE_ATXX(x)
80 #define WEAK_SYMBOL __weak
81 #elif defined(__ARMCC_VERSION)
82 #define LOCATE_AT(x) __attribute__((at(x)))
83 #define WEAK_SYMBOL __attribute__((weak))
84 #elif (defined(__CODE_RED))
85 #define LOCATE_ATX(x) __attribute__((section(".shmem_"#x ",\"aw\",%nobits@")))
86 #define LOCATE_AT(x) LOCATE_ATX(x)
87 #define WEAK_SYMBOL __attribute__((weak))
88 #else
89 #error "Unsupported Compiler/Tool-Chain!"
90 #endif
91
92 #ifdef BOARD_HITEX_EVA_18504350
93 #define debugstr(str) board_uart_out_string(str)
94 #else
95 #define debugstr(str) DEBUGSTR(str)
96 #endif
97
98 /* Number of sectors to read/write */
99 #define NUM_SECTORS 2048
100
101 /* Number of iterations of measurement */
102 #define NUM_ITER 10
103
104 /* Starting sector number for read/write */
105 #define START_SECTOR 32
106
107 /* Buffer size (in bytes) for R/W operations */
108 #define BUFFER_SIZE (NUM_SECTORS * MMC_SECTOR_SIZE)
109
110 /* Buffers to store original data of SD/MMC card.
111 * The data will be stored in this buffer, once read/write measurement
112 * completed, the original contents will be restored into SD/MMC card.
113 * This is done in order avoid corurupting the SD/MMC card
114 */
115 LOCATE_AT(0x28200000) uint32_t Buff_Backup[BUFFER_SIZE/sizeof(uint32_t)];
116
117 /* Buffers for read/write operation */
118 LOCATE_AT(0x28000000) uint32_t Buff_Rd[BUFFER_SIZE/sizeof(uint32_t)];
119 LOCATE_AT(0x28100000) uint32_t Buff_Wr[BUFFER_SIZE/sizeof(uint32_t)];
120
121 /* Measurement data */
122 static uint32_t rd_ticks[NUM_ITER];
123 static uint32_t wr_ticks[NUM_ITER];
124
125 /* SD/MMC card information */
126 /* Number of sectors in SD/MMC card */
127 static int32_t tot_secs;
128
129 /* SDIO wait flag */
130 static volatile int32_t sdio_wait_exit = 0;
131
132 /*****************************************************************************
133 * Public types/enumerations/variables
134 ****************************************************************************/
135
136 /* SDMMC card info structure */
137 mci_card_struct sdcardinfo;
138
139 /*****************************************************************************
140 * Private functions
141 ****************************************************************************/
142
143 /* Delay callback for timed SDIF/SDMMC functions */
144 static void sdmmc_waitms(uint32_t time)
145 {
146 /* In an RTOS, the thread would sleep allowing other threads to run.
147 For standalone operation, we just spin on RI timer */
148 int32_t curr = (int32_t) Chip_RIT_GetCounter(LPC_RITIMER);
149 int32_t final = curr + ((SystemCoreClock / 1000) * time);
150
151 if (final == curr) return;
152
153 if ((final < 0) && (curr > 0)) {
154 while (Chip_RIT_GetCounter(LPC_RITIMER) < (uint32_t) final) {}
155 }
156 else {
157 while ((int32_t) Chip_RIT_GetCounter(LPC_RITIMER) < final) {}
158 }
159
160 return;
161 }
162
168 static void sdmmc_setup_wakeup(void *bits)
169 {
170 uint32_t bit_mask = *((uint32_t *)bits);
171 /* Wait for IRQ - for an RTOS, you would pend on an event here with a IRQ based wakeup. */
172 NVIC_ClearPendingIRQ(SDIO_IRQn);
173 sdio_wait_exit = 0;
174 Chip_SDIF_SetIntMask(LPC_SDMMC, bit_mask);
175 NVIC_EnableIRQ(SDIO_IRQn);
176 }
177
182 static uint32_t sdmmc_irq_driven_wait(void)
183 {
184 uint32_t status;
185
186 /* Wait for event, would be nice to have a timeout, but keep it simple */
187 while (sdio_wait_exit == 0) {}
188
189 /* Get status and clear interrupts */
190 status = Chip_SDIF_GetIntStatus(LPC_SDMMC);
191
192 return status;
193 }
194
195 /* Initialize SD/MMC */
196 static void App_SDMMC_Init()
197 {
198 memset(&sdcardinfo, 0, sizeof(sdcardinfo));
199 sdcardinfo.card_info.evsetup_cb = sdmmc_setup_wakeup;
200 sdcardinfo.card_info.waitfunc_cb = sdmmc_irq_driven_wait;
201 sdcardinfo.card_info.msdelay_func = sdmmc_waitms;
202
203 /* SD/MMC initialization */
204 Board_SDMMC_Init();
205
206 /* The SDIO driver needs to know the SDIO clock rate */
207 Chip_SDIF_Init(LPC_SDMMC);
208 }
209
210 /* Buffer initialisation function */
211 static void Prepare_Buffer(uint32_t value)
212 {
213 uint32_t i;
214
215 for(i = 0; i < (BUFFER_SIZE/sizeof(uint32_t)); i++)
216 {
217 Buff_Rd[i] = 0x0;
218 Buff_Wr[i] = i + value;
219 }
220 }
221
222 #ifdef BOARD_HITEX_EVA_18504350
223 /* Initialize the UART for debugging */
224 static void board_uart_debug_init(void)
225 {
226 /* Hitex EVA A4 is sharing Uart port 0 and SDIO pin so it is needed to use Uart port 1 */
227 Board_UART_Init(LPC_UART1);
228 Chip_UART_SetBaud(LPC_UART1, 115200);
229 Chip_UART_ConfigData(LPC_UART1, UART_DATABIT_8, UART_PARITY_NONE, UART_STOPBIT_1); /* default 8-N-1 */
230
231 /* Enable UART Transmit */
232 Chip_UART_TxCmd(LPC_UART1, ENABLE);
233 }
234
235 /* Sends a character on the UART */
236 static void board_uart_out_ch(char ch)
237 {
238 while (Chip_UART_SendByte(LPC_UART1, (uint8_t) ch) == ERROR) {}
239 }
240
241 /* Sends a string on the UART */
242 static void board_uart_out_string(char *str)
243 {
244 while (*str != '\0') {
245 board_uart_out_ch(*str++);
246 }
247 }
248 #endif
249
250 /* Print the result of a data transfer */
251 static void print_meas_data(void)
252 {
253 static char debugBuf[64];
254 uint64_t tot_sum_rd, tot_sum_wr;
255 uint32_t i, rd_ave, wr_ave, rd_time, wr_time;
256 uint32_t clk = SystemCoreClock/1000000;
257
258 /* Print Number of Interations */
259 debugstr("\r\n=====================\r\n");
260 debugstr("SDMMC Measurements \r\n");
261 debugstr("=====================\r\n");
262 sprintf(debugBuf, "No. of Iterations: %u \r\n", NUM_ITER);
263 debugstr(debugBuf);
264 sprintf(debugBuf, "No. of Sectors for R/W: %u \r\n", NUM_SECTORS);
265 debugstr(debugBuf);
266 sprintf(debugBuf, "Sector size : %u bytes \r\n", MMC_SECTOR_SIZE);
267 debugstr(debugBuf);
268 sprintf(debugBuf, "Data Transferred : %u bytes\r\n", (MMC_SECTOR_SIZE * NUM_SECTORS));
269 debugstr(debugBuf);
270 tot_sum_rd = tot_sum_wr = 0;
271 for(i = 0; i < NUM_ITER; i++) {
272 tot_sum_rd += rd_ticks[i];
273 tot_sum_wr += wr_ticks[i];
274 }
275 rd_ave = tot_sum_rd / NUM_ITER;
276 wr_ave = tot_sum_wr / NUM_ITER;
277 sprintf(debugBuf, "CPU Speed: %lu.%lu MHz\r\n", clk, (SystemCoreClock / 10000) - (clk * 100));
278 debugstr(debugBuf);
279 sprintf(debugBuf, "Ave Ticks for Read: %u \r\n", rd_ave);
280 debugstr(debugBuf);
281 sprintf(debugBuf, "Aver Ticks for Write: %u \r\n", wr_ave);
282 debugstr(debugBuf);
283 rd_time = (rd_ave / clk);
284 wr_time = (wr_ave / clk);
285 sprintf(debugBuf, "READ: Ave Time: %u usecs Ave Speed : %u KB/sec\r\n", rd_time, ((NUM_SECTORS * MMC_SECTOR_SIZE * 1000)/rd_time));
286 debugstr(debugBuf);
287 sprintf(debugBuf, "WRITE:Ave Time: %u usecs Ave Speed : %u KB/sec \r\n", wr_time, ((NUM_SECTORS * MMC_SECTOR_SIZE * 1000)/wr_time));
288 debugstr(debugBuf);
289 }
290
291 /*****************************************************************************
292 * Public functions
293 ****************************************************************************/
294
299 void SDIO_IRQHandler(void)
300 {
301 /* All SD based register handling is done in the callback
302 function. The SDIO interrupt is not enabled as part of this
303 driver and needs to be enabled/disabled in the callbacks or
304 application as needed. This is to allow flexibility with IRQ
305 handling for applicaitons and RTOSes. */
306 /* Set wait exit flag to tell wait function we are ready. In an RTOS,
307 this would trigger wakeup of a thread waiting for the IRQ. */
308 NVIC_DisableIRQ(SDIO_IRQn);
309 sdio_wait_exit = 1;
310 }
311
316 int main(void)
317 {
318 uint32_t rc; /* Result code */
319 int32_t act_read, act_written;
320 uint32_t i, ite_cnt;
321 uint32_t start_time;
322 uint32_t end_time;
323 static char debugBuf[64];
324 uint32_t backup = 0;
325
326 Board_Init();
327 #ifdef BOARD_HITEX_EVA_18504350
328 board_uart_debug_init();
329 #endif
330
331 /* Disable SD/MMC interrupt */
332 NVIC_DisableIRQ(SDIO_IRQn);
333
334 /* Initialise SD/MMC card */
335 App_SDMMC_Init();
336
337 debugstr("\r\n==============================\r\n");
338 debugstr("SDMMC CARD measurement demo\r\n");
339 debugstr("==============================\r\n");
340
341 /* Enable SD/MMC Interrupt */
342 NVIC_DisableIRQ(SDIO_IRQn);
343
344 /* Wait for a card to be inserted (note CD is not on the
345 SDMMC power rail and can be polled without enabling
346 SD slot power */
347 debugstr("\r\nWait till SD/MMC card inserted...\r\n");
348 while (Chip_SDIF_CardNDetect(LPC_SDMMC));
349 debugstr("\r\nSD/MMC Card inserted...\r\n");
350
351 /* Enable slot power */
352 Chip_SDIF_PowerOn(LPC_SDMMC);
353
354 /* Enumerate the SDMMC card once detected.
355 * Note this function may block for a little while. */
356 rc = Chip_SDMMC_Acquire(LPC_SDMMC, &sdcardinfo);
357 if (!rc) {
358 debugstr("SD/MMC Card enumeration failed! ..\r\n");
359 goto error_exit;
360 }
361
362 /* Check if Write Protected */
363 rc = Chip_SDIF_CardWpOn(LPC_SDMMC);
364 if (rc) {
365 debugstr("SDMMC Card is write protected!, so tests can not continue..\r\n");
366 goto error_exit;
367 }
368
369 /* Read Card information */
370 tot_secs = Chip_SDMMC_GetDeviceBlocks(LPC_SDMMC);
371
372 /* Make sure that the sectors are withing the card size */
373 if((START_SECTOR + NUM_SECTORS) >= tot_secs) {
374 debugstr("Out of range parameters! ..\r\n");
375 goto error_exit;
376 }
377
378 /* Take back up of SD/MMC card contents so that
379 * it can be restored so that SD/MMC card is not corrupted
380 */
381 debugstr("\r\nTaking back up of card.. \r\n");
382 act_read = Chip_SDMMC_ReadBlocks(LPC_SDMMC, (void *)Buff_Backup, START_SECTOR, NUM_SECTORS);
383 if(act_read == 0) {
384 debugstr("Taking back up of card failed!.. \r\n");
385 goto error_exit;
386 }
387
388 ite_cnt = 0;
389 backup = 1;
390 while(ite_cnt < NUM_ITER) {
391 /* Prepare R/W buffers */
392 Prepare_Buffer(ite_cnt);
393
394 /* Write data to SD/MMC card */
395 start_time = Chip_RIT_GetCounter(LPC_RITIMER);
396 act_written = Chip_SDMMC_WriteBlocks(LPC_SDMMC, (void *)Buff_Wr, START_SECTOR, NUM_SECTORS);
397 end_time = Chip_RIT_GetCounter(LPC_RITIMER);
398 if(act_written == 0) {
399 sprintf(debugBuf, "WriteBlocks failed for Iter: %u! \r\n", ite_cnt);
400 debugstr(debugBuf);
401 goto error_exit;
402 }
403
404 if(end_time < start_time) {
405 continue;
406 }
407 else {
408 wr_ticks[ite_cnt] = end_time - start_time;
409 }
410
411 /* Read data from SD/MMC card */
412 start_time = Chip_RIT_GetCounter(LPC_RITIMER);
413 act_written = Chip_SDMMC_ReadBlocks(LPC_SDMMC, (void *)Buff_Rd, START_SECTOR, NUM_SECTORS);
414 end_time = Chip_RIT_GetCounter(LPC_RITIMER);
415 if(act_read == 0) {
416 sprintf(debugBuf, "ReadBlocks failed for Iter: %u! \r\n", ite_cnt);
417 debugstr(debugBuf);
418 goto error_exit;
419 }
420
421 if(end_time < start_time) {
422 continue;
423 }
424 else {
425 rd_ticks[ite_cnt] = end_time - start_time;
426 }
427
428 /* Comapre data */
429 for(i = 0; i < (BUFFER_SIZE/sizeof(uint32_t)); i++)
430 {
431 if(Buff_Rd[i] != Buff_Wr[i])
432 {
433 sprintf(debugBuf, "Data mismacth: ind: %u Rd: 0x%x Wr: 0x%x \r\n", i, Buff_Rd[i], Buff_Wr[i]);
434 debugstr(debugBuf);
435 goto error_exit;
436 }
437 }
438 ite_cnt++;
439 }
440
441 /* Print Measurement onto UART */
442 print_meas_data();
443
444 error_exit:
445 /* Restore if back up taken */
446 if(backup) {
447 debugstr("\r\nRestoring the contents of SDMMC card... \r\n");
448 act_written = Chip_SDMMC_WriteBlocks(LPC_SDMMC, (void *)Buff_Backup, START_SECTOR, NUM_SECTORS);
449 if(act_written == 0) {
450 debugstr("Restoring contents failed!.. \r\n");
451 }
452 }
453
454 debugstr("\r\n========================================\r\n");
455 debugstr("SDMMC CARD measurement demo completed\r\n");
456 debugstr("========================================\r\n");
457
458 /* Wait forever */
459 for (;; ) {}
460 }
461