]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_MPU_M23_Nuvoton_NuMaker_PFM_M2351_IAR_GCC/Nuvoton_Code/StdDriver/src/sdh.c
Add Cortex M23 GCC and IAR ports. Add demo projects for Nuvoton NuMaker-PFM-2351.
[freertos] / FreeRTOS / Demo / CORTEX_MPU_M23_Nuvoton_NuMaker_PFM_M2351_IAR_GCC / Nuvoton_Code / StdDriver / src / sdh.c
1 /**************************************************************************//**\r
2  * @file     SDH.c\r
3  * @version  V1.00\r
4  * @brief    M2351 SDH driver source file\r
5  *\r
6  * @note\r
7  * @copyright (C) 2017 Nuvoton Technology Corp. All rights reserved.\r
8 *****************************************************************************/\r
9 #include <stdio.h>\r
10 #include <stdlib.h>\r
11 #include <string.h>\r
12 #include "NuMicro.h"\r
13 \r
14 #if defined (__ICCARM__)\r
15 # pragma diag_suppress=Pm073, Pm143        /* Misra C 2004 rule 14.7 */\r
16 #endif\r
17 \r
18 \r
19 /** @addtogroup Standard_Driver Standard Driver\r
20   @{\r
21 */\r
22 \r
23 /** @addtogroup SDH_Driver SDH Driver\r
24   @{\r
25 */\r
26 \r
27 /** @addtogroup SDH_EXPORTED_FUNCTIONS SDH Exported Functions\r
28   @{\r
29 */\r
30 \r
31 #define SDH_BLOCK_SIZE   512UL\r
32 \r
33 /* #define DEBUG_PRINTF printf */\r
34 #define DEBUG_PRINTF(...)\r
35 \r
36 /** @cond HIDDEN_SYMBOLS */\r
37 \r
38 /* global variables */\r
39 /* For response R3 (such as ACMD41, CRC-7 is invalid; but SD controller will still */\r
40 /* calculate CRC-7 and get an error result, software should ignore this error and clear SDISR [CRC_IF] flag */\r
41 /* _sd_uR3_CMD is the flag for it. 1 means software should ignore CRC-7 error */\r
42 uint8_t g_u8R3Flag = 0UL;\r
43 uint8_t volatile g_u8SDDataReadyFlag = (uint8_t)FALSE;\r
44 \r
45 static uint32_t _SDH_uR7_CMD = 0UL;\r
46 static uint32_t _SDH_ReferenceClock;\r
47 \r
48 #if defined ( __ICCARM__ ) /*!< IAR Compiler */\r
49 #pragma data_alignment = 4\r
50 static uint8_t _SDH_ucSDHCBuffer[512];\r
51 #else\r
52 static __attribute__((aligned)) uint8_t _SDH_ucSDHCBuffer[512];\r
53 #endif\r
54 \r
55 /* Declare these functions here to avoid MISRA C 2004 rule 8.1 error */\r
56 void SDH_CheckRB(SDH_T *sdh);\r
57 uint32_t SDH_SDCommand(SDH_T *sdh, uint32_t u32Cmd, uint32_t u32Arg);\r
58 uint32_t SDH_SDCmdAndRsp(SDH_T *sdh, uint32_t u32Cmd, uint32_t u32Arg, uint32_t u32TickCount);\r
59 uint32_t SDH_Swap32(uint32_t u32Val);\r
60 uint32_t SDH_SDCmdAndRsp2(SDH_T *sdh, uint32_t u32Cmd, uint32_t u32Arg, uint32_t pu32R2ptr[]);\r
61 uint32_t SDH_SDCmdAndRspDataIn(SDH_T *sdh, uint32_t u32Cmd, uint32_t u32Arg);\r
62 void SDH_Set_clock(SDH_T *sdh, uint32_t u32SDClockKhz);\r
63 uint32_t SDH_CardDetection(SDH_T *sdh);\r
64 uint32_t SDH_Init(SDH_T *sdh);\r
65 uint32_t SDH_SwitchToHighSpeed(SDH_T *sdh, SDH_INFO_T *pSD);\r
66 uint32_t SDH_SelectCardType(SDH_T *sdh);\r
67 void SDH_Get_SD_info(SDH_T *sdh);\r
68 \r
69 int SDH_ok = 0;\r
70 \r
71 SDH_INFO_T SD0;\r
72 \r
73 void SDH_CheckRB(SDH_T *sdh)\r
74 {\r
75     while(1)\r
76     {\r
77         sdh->CTL |= SDH_CTL_CLK8OEN_Msk;\r
78         while(sdh->CTL & SDH_CTL_CLK8OEN_Msk) {}\r
79         if(sdh->INTSTS & SDH_INTSTS_DAT0STS_Msk)\r
80         {\r
81             break;\r
82         }\r
83     }\r
84 }\r
85 \r
86 \r
87 uint32_t SDH_SDCommand(SDH_T *sdh, uint32_t u32Cmd, uint32_t u32Arg)\r
88 {\r
89     SDH_INFO_T *pSD;\r
90     volatile uint32_t u32Status = Successful;\r
91 \r
92     /* M2351 is only support SDH0 */\r
93     pSD = &SD0;\r
94 \r
95     sdh->CMDARG = u32Arg;\r
96     sdh->CTL = (sdh->CTL & (~SDH_CTL_CMDCODE_Msk)) | (u32Cmd << 8) | (SDH_CTL_COEN_Msk);\r
97 \r
98     while(sdh->CTL & SDH_CTL_COEN_Msk)\r
99     {\r
100         if(pSD->IsCardInsert == (uint32_t)FALSE)\r
101         {\r
102             u32Status = SDH_NO_SD_CARD;\r
103         }\r
104     }\r
105     return u32Status;\r
106 }\r
107 \r
108 \r
109 uint32_t SDH_SDCmdAndRsp(SDH_T *sdh, uint32_t u32Cmd, uint32_t u32Arg, uint32_t u32TickCount)\r
110 {\r
111     SDH_INFO_T *pSD;\r
112 \r
113     /* M2351 is only support SDH0 */\r
114     pSD = &SD0;\r
115 \r
116     sdh->CMDARG = u32Arg;\r
117     sdh->CTL = (sdh->CTL & (~SDH_CTL_CMDCODE_Msk)) | (u32Cmd << 8) | (SDH_CTL_COEN_Msk | SDH_CTL_RIEN_Msk);\r
118 \r
119     if(u32TickCount > 0UL)\r
120     {\r
121         while(sdh->CTL & SDH_CTL_RIEN_Msk)\r
122         {\r
123             if(u32TickCount-- == 0UL)\r
124             {\r
125                 sdh->CTL |= SDH_CTL_CTLRST_Msk; /* reset SD engine */\r
126                 return 2UL;\r
127             }\r
128             if(pSD->IsCardInsert == (uint8_t)FALSE)\r
129             {\r
130                 return SDH_NO_SD_CARD;\r
131             }\r
132         }\r
133     }\r
134     else\r
135     {\r
136         while(sdh->CTL & SDH_CTL_RIEN_Msk)\r
137         {\r
138             if(pSD->IsCardInsert == (uint8_t)FALSE)\r
139             {\r
140                 return SDH_NO_SD_CARD;\r
141             }\r
142         }\r
143     }\r
144 \r
145     if(_SDH_uR7_CMD)\r
146     {\r
147         if((sdh->RESP1 & 0xffUL) != 0x55UL)\r
148         {\r
149             if((sdh->RESP0 & 0xfUL) != 0x01UL)\r
150             {\r
151                 _SDH_uR7_CMD = 0UL;\r
152                 return SDH_CMD8_ERROR;\r
153             }\r
154         }\r
155     }\r
156 \r
157     if(!g_u8R3Flag)\r
158     {\r
159         if(sdh->INTSTS & SDH_INTSTS_CRC7_Msk)      /* check CRC7 */\r
160         {\r
161             return Successful;\r
162         }\r
163         else\r
164         {\r
165             return SDH_CRC7_ERROR;\r
166         }\r
167     }\r
168     else     /* ignore CRC error for R3 case */\r
169     {\r
170         g_u8R3Flag = 0UL;\r
171         sdh->INTSTS = SDH_INTSTS_CRCIF_Msk;\r
172         return Successful;\r
173     }\r
174 }\r
175 \r
176 \r
177 uint32_t SDH_Swap32(uint32_t u32Val)\r
178 {\r
179     uint32_t u32Buf;\r
180 \r
181     u32Buf = u32Val;\r
182     u32Val <<= 24;\r
183     u32Val |= (u32Buf << 8) & 0xff0000UL;\r
184     u32Val |= (u32Buf >> 8) & 0xff00UL;\r
185     u32Val |= (u32Buf >> 24) & 0xffUL;\r
186     return u32Buf;\r
187 }\r
188 \r
189 /* Get 16 bytes CID or CSD */\r
190 uint32_t SDH_SDCmdAndRsp2(SDH_T *sdh, uint32_t u32Cmd, uint32_t u32Arg, uint32_t pu32R2ptr[])\r
191 {\r
192     uint32_t i;\r
193     uint32_t au32TmpBuf[5];\r
194     SDH_INFO_T *pSD;\r
195 \r
196     /* M2351 is only support SDH0 */\r
197     pSD = &SD0;\r
198 \r
199     sdh->CMDARG = u32Arg;\r
200     sdh->CTL = (sdh->CTL & (~SDH_CTL_CMDCODE_Msk)) | (u32Cmd << 8) | (SDH_CTL_COEN_Msk | SDH_CTL_R2EN_Msk);\r
201 \r
202     while(sdh->CTL & SDH_CTL_R2EN_Msk)\r
203     {\r
204         if(pSD->IsCardInsert == (uint8_t)FALSE)\r
205         {\r
206             return SDH_NO_SD_CARD;\r
207         }\r
208     }\r
209 \r
210     if(sdh->INTSTS & SDH_INTSTS_CRC7_Msk)\r
211     {\r
212         for(i = 0UL; i < 5UL; i++)\r
213         {\r
214             au32TmpBuf[i] = SDH_Swap32(sdh->FB[i]);\r
215         }\r
216         for(i = 0UL; i < 4UL; i++)\r
217         {\r
218             pu32R2ptr[i] = ((au32TmpBuf[i] & 0x00ffffffUL) << 8) | ((au32TmpBuf[i + 1UL] & 0xff000000UL) >> 24);\r
219         }\r
220         return Successful;\r
221     }\r
222     else\r
223     {\r
224         return SDH_CRC7_ERROR;\r
225     }\r
226 }\r
227 \r
228 \r
229 uint32_t SDH_SDCmdAndRspDataIn(SDH_T *sdh, uint32_t u32Cmd, uint32_t u32Arg)\r
230 {\r
231     SDH_INFO_T *pSD;\r
232 \r
233     /* M2351 is only support SDH0 */\r
234     pSD = &SD0;\r
235 \r
236     sdh->CMDARG = u32Arg;\r
237     sdh->CTL = (sdh->CTL & (~SDH_CTL_CMDCODE_Msk)) | ((uint32_t)u32Cmd << 8) |\r
238                (SDH_CTL_COEN_Msk | SDH_CTL_RIEN_Msk | SDH_CTL_DIEN_Msk);\r
239 \r
240     while(sdh->CTL & SDH_CTL_RIEN_Msk)\r
241     {\r
242         if(pSD->IsCardInsert == (uint32_t)FALSE)\r
243         {\r
244             return SDH_NO_SD_CARD;\r
245         }\r
246     }\r
247 \r
248     while(sdh->CTL & SDH_CTL_DIEN_Msk)\r
249     {\r
250         if(pSD->IsCardInsert == (uint32_t)FALSE)\r
251         {\r
252             return SDH_NO_SD_CARD;\r
253         }\r
254     }\r
255 \r
256     if(!(sdh->INTSTS & SDH_INTSTS_CRC7_Msk))       /* check CRC7 */\r
257     {\r
258         return SDH_CRC7_ERROR;\r
259     }\r
260 \r
261     if(!(sdh->INTSTS & SDH_INTSTS_CRC16_Msk))      /* check CRC16 */\r
262     {\r
263         return SDH_CRC16_ERROR;\r
264     }\r
265 \r
266     return Successful;\r
267 }\r
268 \r
269 /* there are 8 bits for divider0, maximum is 256 */\r
270 #define SDH_CLK_DIV0_MAX     256UL\r
271 \r
272 void SDH_Set_clock(SDH_T *sdh, uint32_t u32SDClockKhz)\r
273 {\r
274     if(!(__PC() & (1UL << 28)))\r
275     {\r
276         uint32_t u32Rate, u32Div1;\r
277         static uint32_t u32SDClkSrc = 0UL;\r
278 \r
279         /* M2351 is only support SDH0 */\r
280         u32SDClkSrc = (CLK->CLKSEL0 & CLK_CLKSEL0_SDH0SEL_Msk);\r
281         if(u32SDClkSrc == CLK_CLKSEL0_SDH0SEL_HXT)\r
282         {\r
283             _SDH_ReferenceClock = (CLK_GetHXTFreq() / 1000UL);\r
284         }\r
285         else if(u32SDClkSrc == CLK_CLKSEL0_SDH0SEL_HIRC)\r
286         {\r
287             _SDH_ReferenceClock = (__HIRC / 1000UL);\r
288         }\r
289         else if(u32SDClkSrc == CLK_CLKSEL0_SDH0SEL_PLL)\r
290         {\r
291             _SDH_ReferenceClock = (CLK_GetPLLClockFreq() / 1000UL);\r
292         }\r
293         else if(u32SDClkSrc == CLK_CLKSEL0_SDH0SEL_HCLK)\r
294         {\r
295             _SDH_ReferenceClock = (CLK_GetHCLKFreq() / 1000UL);\r
296         }\r
297 \r
298         if(u32SDClockKhz >= 50000UL)\r
299         {\r
300             u32SDClockKhz = 50000UL;\r
301         }\r
302         u32Rate = _SDH_ReferenceClock / u32SDClockKhz;\r
303 \r
304         /* choose slower clock if system clock cannot divisible by wanted clock */\r
305         if(_SDH_ReferenceClock % u32SDClockKhz != 0UL)\r
306         {\r
307             u32Rate++;\r
308         }\r
309 \r
310         if(u32Rate >= SDH_CLK_DIV0_MAX)\r
311         {\r
312             u32Rate = SDH_CLK_DIV0_MAX;\r
313         }\r
314 \r
315         /* --- calculate the second divider CLKDIV0[SDHOST_N] */\r
316         if(u32Rate == 0UL)\r
317         {\r
318             u32Div1 = 0UL;\r
319         }\r
320         else\r
321         {\r
322             u32Div1 = ((u32Rate - 1UL) & 0xFFUL);\r
323         }\r
324 \r
325         /* --- setup register */\r
326         /* M2351 is only support SDH0 */\r
327         CLK->CLKDIV0 &= ~CLK_CLKDIV0_SDH0DIV_Msk;\r
328         CLK->CLKDIV0 |= (u32Div1 << CLK_CLKDIV0_SDH0DIV_Pos);\r
329     }\r
330 }\r
331 \r
332 uint32_t SDH_CardDetection(SDH_T *sdh)\r
333 {\r
334     uint32_t i, u32Status = (uint32_t)TRUE;\r
335     SDH_INFO_T *pSD;\r
336 \r
337     /* M2351 is only support SDH0 */\r
338     pSD = &SD0;\r
339 \r
340     if(sdh->INTEN & SDH_INTEN_CDSRC_Msk)   /* Card detect pin from GPIO */\r
341     {\r
342         if(sdh->INTSTS & SDH_INTSTS_CDSTS_Msk)   /* Card remove */\r
343         {\r
344             pSD->IsCardInsert = (uint8_t)FALSE;\r
345             u32Status = (uint32_t)FALSE;\r
346         }\r
347         else\r
348         {\r
349             pSD->IsCardInsert = (uint8_t)TRUE;\r
350         }\r
351     }\r
352     else if(!(sdh->INTEN & SDH_INTEN_CDSRC_Msk))\r
353     {\r
354         sdh->CTL |= SDH_CTL_CLKKEEP_Msk;\r
355         for(i = 0UL; i < 5000UL; i++) {}\r
356 \r
357         if(sdh->INTSTS & SDH_INTSTS_CDSTS_Msk) /* Card insert */\r
358         {\r
359             pSD->IsCardInsert = (uint8_t)TRUE;\r
360         }\r
361         else\r
362         {\r
363             pSD->IsCardInsert = (uint8_t)FALSE;\r
364             u32Status = (uint32_t)FALSE;\r
365         }\r
366 \r
367         sdh->CTL &= ~SDH_CTL_CLKKEEP_Msk;\r
368     }\r
369 \r
370     return u32Status;\r
371 }\r
372 \r
373 \r
374 /* Initial */\r
375 uint32_t SDH_Init(SDH_T *sdh)\r
376 {\r
377     uint32_t volatile i, u32Status;\r
378     uint32_t u32Resp;\r
379     uint32_t au32CIDBuffer[4];\r
380     uint32_t volatile u32CmdTimeOut;\r
381     SDH_INFO_T *pSD;\r
382 \r
383     /* M2351 is only support SDH0 */\r
384     pSD = &SD0;\r
385 \r
386     /* set the clock to 300KHz */\r
387     SDH_Set_clock(sdh, 300UL);\r
388 \r
389     /* power ON 74 clock */\r
390     sdh->CTL |= SDH_CTL_CLK74OEN_Msk;\r
391 \r
392     while(sdh->CTL & SDH_CTL_CLK74OEN_Msk)\r
393     {\r
394         if(pSD->IsCardInsert == (uint8_t)FALSE)\r
395         {\r
396             return SDH_NO_SD_CARD;\r
397         }\r
398     }\r
399 \r
400     SDH_SDCommand(sdh, 0UL, 0UL);        /* reset all cards */\r
401     for(i = 0x1000UL; i > 0UL; i--) {}\r
402 \r
403     /* initial SDHC */\r
404     _SDH_uR7_CMD = 1UL;\r
405     u32CmdTimeOut = 0xFFFFFUL;\r
406 \r
407     i = SDH_SDCmdAndRsp(sdh, 8UL, 0x00000155UL, u32CmdTimeOut);\r
408     if(i == Successful)\r
409     {\r
410         /* SD 2.0 */\r
411         SDH_SDCmdAndRsp(sdh, 55UL, 0x00UL, u32CmdTimeOut);\r
412         g_u8R3Flag = 1UL;\r
413         SDH_SDCmdAndRsp(sdh, 41UL, 0x40ff8000UL, u32CmdTimeOut); /* 2.7v-3.6v */\r
414         u32Resp = sdh->RESP0;\r
415 \r
416         while(!(u32Resp & 0x00800000UL))         /* check if card is ready */\r
417         {\r
418             SDH_SDCmdAndRsp(sdh, 55UL, 0x00UL, u32CmdTimeOut);\r
419             g_u8R3Flag = 1UL;\r
420             SDH_SDCmdAndRsp(sdh, 41UL, 0x40ff8000UL, u32CmdTimeOut); /* 3.0v-3.4v */\r
421             u32Resp = sdh->RESP0;\r
422         }\r
423         if(u32Resp & 0x00400000UL)\r
424         {\r
425             pSD->CardType = SDH_TYPE_SD_HIGH;\r
426         }\r
427         else\r
428         {\r
429             pSD->CardType = SDH_TYPE_SD_LOW;\r
430         }\r
431     }\r
432     else\r
433     {\r
434         /* SD 1.1 */\r
435         SDH_SDCommand(sdh, 0UL, 0UL);        /* reset all cards */\r
436         for(i = 0x100UL; i > 0UL; i--) {}\r
437 \r
438         i = SDH_SDCmdAndRsp(sdh, 55UL, 0x00UL, u32CmdTimeOut);\r
439         if(i == 2UL)      /* MMC memory */\r
440         {\r
441             SDH_SDCommand(sdh, 0UL, 0UL);        /* reset */\r
442             for(i = 0x100UL; i > 0UL; i--) {}\r
443 \r
444             g_u8R3Flag = 1UL;\r
445 \r
446             if(SDH_SDCmdAndRsp(sdh, 1UL, 0x40ff8000UL, u32CmdTimeOut) != 2UL)     /* eMMC memory */\r
447             {\r
448                 u32Resp = sdh->RESP0;\r
449                 while(!(u32Resp & 0x00800000UL))         /* check if card is ready */\r
450                 {\r
451                     g_u8R3Flag = 1UL;\r
452 \r
453                     SDH_SDCmdAndRsp(sdh, 1UL, 0x40ff8000UL, u32CmdTimeOut);      /* high voltage */\r
454                     u32Resp = sdh->RESP0;\r
455                 }\r
456 \r
457                 if(u32Resp & 0x00400000UL)\r
458                 {\r
459                     pSD->CardType = SDH_TYPE_EMMC;\r
460                 }\r
461                 else\r
462                 {\r
463                     pSD->CardType = SDH_TYPE_MMC;\r
464                 }\r
465             }\r
466             else\r
467             {\r
468                 pSD->CardType = SDH_TYPE_UNKNOWN;\r
469                 return SDH_ERR_DEVICE;\r
470             }\r
471         }\r
472         else if(i == 0UL)      /* SD Memory */\r
473         {\r
474             g_u8R3Flag = 1UL;\r
475             SDH_SDCmdAndRsp(sdh, 41UL, 0x00ff8000UL, u32CmdTimeOut); /* 3.0v-3.4v */\r
476             u32Resp = sdh->RESP0;\r
477             while(!(u32Resp & 0x00800000UL))         /* check if card is ready */\r
478             {\r
479                 SDH_SDCmdAndRsp(sdh, 55UL, 0x00UL, u32CmdTimeOut);\r
480                 g_u8R3Flag = 1UL;\r
481                 SDH_SDCmdAndRsp(sdh, 41UL, 0x00ff8000UL, u32CmdTimeOut); /* 3.0v-3.4v */\r
482                 u32Resp = sdh->RESP0;\r
483             }\r
484             pSD->CardType = SDH_TYPE_SD_LOW;\r
485         }\r
486         else\r
487         {\r
488             pSD->CardType = SDH_TYPE_UNKNOWN;\r
489             return SDH_INIT_ERROR;\r
490         }\r
491     }\r
492 \r
493     /* CMD2, CMD3 */\r
494     if(pSD->CardType != SDH_TYPE_UNKNOWN)\r
495     {\r
496         SDH_SDCmdAndRsp2(sdh, 2UL, 0x00UL, au32CIDBuffer);\r
497         if((pSD->CardType == SDH_TYPE_MMC) || (pSD->CardType == SDH_TYPE_EMMC))\r
498         {\r
499             if((u32Status = SDH_SDCmdAndRsp(sdh, 3UL, 0x10000UL, 0UL)) != Successful)         /* set RCA */\r
500             {\r
501                 return u32Status;\r
502             }\r
503             pSD->RCA = 0x10000UL;\r
504         }\r
505         else\r
506         {\r
507             if((u32Status = SDH_SDCmdAndRsp(sdh, 3UL, 0x00UL, 0UL)) != Successful)        /* get RCA */\r
508             {\r
509                 return u32Status;\r
510             }\r
511             else\r
512             {\r
513                 pSD->RCA = (sdh->RESP0 << 8) & 0xffff0000UL;\r
514             }\r
515         }\r
516     }\r
517 \r
518     return Successful;\r
519 }\r
520 \r
521 \r
522 uint32_t SDH_SwitchToHighSpeed(SDH_T *sdh, SDH_INFO_T *pSD)\r
523 {\r
524     uint32_t volatile u32Status = 0UL;\r
525     uint16_t u16CurrentComsumption, u16BusyStatus0;\r
526 \r
527     sdh->DMASA = (uint32_t)_SDH_ucSDHCBuffer;    /* set DMA transfer starting address */\r
528     sdh->BLEN = 63UL;    /* 512 bit */\r
529 \r
530     if((u32Status = SDH_SDCmdAndRspDataIn(sdh, 6UL, 0x00ffff01UL)) != Successful)\r
531     {\r
532         return Fail;\r
533     }\r
534 \r
535     u16CurrentComsumption = (uint16_t)_SDH_ucSDHCBuffer[0] << 8;\r
536     u16CurrentComsumption |= (uint16_t)_SDH_ucSDHCBuffer[1];\r
537     if(!u16CurrentComsumption)\r
538     {\r
539         return Fail;\r
540     }\r
541 \r
542     u16BusyStatus0 = (uint16_t)_SDH_ucSDHCBuffer[28] << 8;\r
543     u16BusyStatus0 |= (uint16_t)_SDH_ucSDHCBuffer[29];\r
544 \r
545     if(!u16BusyStatus0)    /* function ready */\r
546     {\r
547         sdh->DMASA = (uint32_t)_SDH_ucSDHCBuffer;        /* set DMA transfer starting address */\r
548         sdh->BLEN = 63UL;    /* 512 bit */\r
549 \r
550         if((u32Status = SDH_SDCmdAndRspDataIn(sdh, 6UL, 0x80ffff01UL)) != Successful)\r
551         {\r
552             return Fail;\r
553         }\r
554 \r
555         /* function change timing: 8 clocks */\r
556         sdh->CTL |= SDH_CTL_CLK8OEN_Msk;\r
557         while(sdh->CTL & SDH_CTL_CLK8OEN_Msk) {}\r
558 \r
559         u16CurrentComsumption = (uint16_t)_SDH_ucSDHCBuffer[0] << 8;\r
560         u16CurrentComsumption |= (uint16_t)_SDH_ucSDHCBuffer[1];\r
561         if(!u16CurrentComsumption)\r
562         {\r
563             return Fail;\r
564         }\r
565 \r
566         return Successful;\r
567     }\r
568     else\r
569     {\r
570         return Fail;\r
571     }\r
572 }\r
573 \r
574 \r
575 uint32_t SDH_SelectCardType(SDH_T *sdh)\r
576 {\r
577     uint32_t volatile u32Status = 0UL;\r
578     uint32_t u32Param;\r
579     SDH_INFO_T *pSD;\r
580 \r
581     /* M2351 is only support SDH0 */\r
582     pSD = &SD0;\r
583 \r
584     if((u32Status = SDH_SDCmdAndRsp(sdh, 7UL, pSD->RCA, 0UL)) != Successful)\r
585     {\r
586         return u32Status;\r
587     }\r
588 \r
589     SDH_CheckRB(sdh);\r
590 \r
591     /* if SD card set 4bit */\r
592     if(pSD->CardType == SDH_TYPE_SD_HIGH)\r
593     {\r
594         sdh->DMASA = (uint32_t)_SDH_ucSDHCBuffer;    /* set DMA transfer starting address */\r
595         sdh->BLEN = 0x07UL;  /* 64 bit */\r
596 \r
597         if((u32Status = SDH_SDCmdAndRsp(sdh, 55UL, pSD->RCA, 0UL)) != Successful)\r
598         {\r
599             return u32Status;\r
600         }\r
601 \r
602         sdh->DMACTL |= 0x2;\r
603         while(sdh->DMACTL & 0x2) {};\r
604 \r
605         if((u32Status = SDH_SDCmdAndRspDataIn(sdh, 51UL, 0x00UL)) != Successful)\r
606         {\r
607             return u32Status;\r
608         }\r
609 \r
610         if((_SDH_ucSDHCBuffer[0] & 0xfUL) == 0xfUL)\r
611         {\r
612             u32Status = SDH_SwitchToHighSpeed(sdh, pSD);\r
613             if(u32Status == Successful)\r
614             {\r
615                 /* divider */\r
616                 SDH_Set_clock(sdh, SDHC_FREQ);\r
617             }\r
618         }\r
619 \r
620         if((u32Status = SDH_SDCmdAndRsp(sdh, 55UL, pSD->RCA, 0UL)) != Successful)\r
621         {\r
622             return u32Status;\r
623         }\r
624         if((u32Status = SDH_SDCmdAndRsp(sdh, 6UL, 0x02UL, 0UL)) != Successful)    /* set bus width */\r
625         {\r
626             return u32Status;\r
627         }\r
628 \r
629         sdh->CTL |= SDH_CTL_DBW_Msk;\r
630     }\r
631     else if(pSD->CardType == SDH_TYPE_SD_LOW)\r
632     {\r
633         sdh->DMASA = (uint32_t) _SDH_ucSDHCBuffer; /* set DMA transfer starting address */\r
634         sdh->BLEN = 0x07UL;  /* 64 bit */\r
635 \r
636         if((u32Status = SDH_SDCmdAndRsp(sdh, 55UL, pSD->RCA, 0UL)) != Successful)\r
637         {\r
638             return u32Status;\r
639         }\r
640         if((u32Status = SDH_SDCmdAndRspDataIn(sdh, 51UL, 0x00UL)) != Successful)\r
641         {\r
642             return u32Status;\r
643         }\r
644 \r
645         /* set data bus width. ACMD6 for SD card, SDCR_DBW for host. */\r
646         if((u32Status = SDH_SDCmdAndRsp(sdh, 55UL, pSD->RCA, 0UL)) != Successful)\r
647         {\r
648             return u32Status;\r
649         }\r
650 \r
651         if((u32Status = SDH_SDCmdAndRsp(sdh, 6UL, 0x02UL, 0UL)) != Successful)    /* set bus width */\r
652         {\r
653             return u32Status;\r
654         }\r
655 \r
656         sdh->CTL |= SDH_CTL_DBW_Msk;\r
657     }\r
658     else if((pSD->CardType == SDH_TYPE_MMC) || (pSD->CardType == SDH_TYPE_EMMC))\r
659     {\r
660 \r
661         if(pSD->CardType == SDH_TYPE_MMC)\r
662         {\r
663             sdh->CTL &= ~SDH_CTL_DBW_Msk;\r
664         }\r
665 \r
666         /* --- sent CMD6 to MMC card to set bus width to 4 bits mode */\r
667         /* set CMD6 argument Access field to 3, Index to 183, Value to 1 (4-bit mode) */\r
668         u32Param = (3UL << 24) | (183UL << 16) | (1UL << 8);\r
669         if((u32Status = SDH_SDCmdAndRsp(sdh, 6UL, u32Param, 0UL)) != Successful)\r
670         {\r
671             return u32Status;\r
672         }\r
673         SDH_CheckRB(sdh);\r
674 \r
675         sdh->CTL |= SDH_CTL_DBW_Msk; /* set bus width to 4-bit mode for SD host controller */\r
676     }\r
677 \r
678     if((u32Status = SDH_SDCmdAndRsp(sdh, 16UL, SDH_BLOCK_SIZE, 0UL)) != Successful)  /* set block length */\r
679     {\r
680         return u32Status;\r
681     }\r
682     sdh->BLEN = SDH_BLOCK_SIZE - 1UL;           /* set the block size */\r
683 \r
684     SDH_SDCommand(sdh, 7UL, 0UL);\r
685     sdh->CTL |= SDH_CTL_CLK8OEN_Msk;\r
686     while(sdh->CTL & SDH_CTL_CLK8OEN_Msk) {}\r
687 \r
688     sdh->INTEN |= SDH_INTEN_BLKDIEN_Msk;\r
689 \r
690     return Successful;\r
691 }\r
692 \r
693 void SDH_Get_SD_info(SDH_T *sdh)\r
694 {\r
695     uint32_t u32RLen, u32CSize, u32Mult, u32Size;\r
696     uint32_t au32Buffer[4];\r
697     SDH_INFO_T *pSD;\r
698 \r
699     /* M2351 is only support SDH0 */\r
700     pSD = &SD0;\r
701 \r
702     SDH_SDCmdAndRsp2(sdh, 9UL, pSD->RCA, au32Buffer);\r
703 \r
704     if((pSD->CardType == SDH_TYPE_MMC) || (pSD->CardType == SDH_TYPE_EMMC))\r
705     {\r
706         /* for MMC/eMMC card */\r
707         if((au32Buffer[0] & 0xc0000000UL) == 0xc0000000UL)\r
708         {\r
709             /* CSD_STRUCTURE [127:126] is 3 */\r
710             /* CSD version depend on EXT_CSD register in eMMC v4.4 for card size > 2GB */\r
711             SDH_SDCmdAndRsp(sdh, 7UL, pSD->RCA, 0UL);\r
712 \r
713             sdh->DMASA = (uint32_t)_SDH_ucSDHCBuffer;  /* set DMA transfer starting address */\r
714             sdh->BLEN = 511UL;  /* read 512 bytes for EXT_CSD */\r
715 \r
716             if(SDH_SDCmdAndRspDataIn(sdh, 8UL, 0x00UL) != Successful)\r
717             {\r
718                 return;\r
719             }\r
720 \r
721             SDH_SDCommand(sdh, 7UL, 0UL);\r
722             sdh->CTL |= SDH_CTL_CLK8OEN_Msk;\r
723             while(sdh->CTL & SDH_CTL_CLK8OEN_Msk) {}\r
724 \r
725             pSD->totalSectorN = (uint32_t)_SDH_ucSDHCBuffer[215] << 24;\r
726             pSD->totalSectorN |= (uint32_t)_SDH_ucSDHCBuffer[214] << 16;\r
727             pSD->totalSectorN |= (uint32_t)_SDH_ucSDHCBuffer[213] << 8;\r
728             pSD->totalSectorN |= (uint32_t)_SDH_ucSDHCBuffer[212];\r
729             pSD->diskSize = pSD->totalSectorN / 2UL;\r
730         }\r
731         else\r
732         {\r
733             /* CSD version v1.0/1.1/1.2 in eMMC v4.4 spec for card size <= 2GB */\r
734             u32RLen = (au32Buffer[1] & 0x000f0000UL) >> 16;\r
735             u32CSize = ((au32Buffer[1] & 0x000003ffUL) << 2) | ((au32Buffer[2] & 0xc0000000UL) >> 30);\r
736             u32Mult = (au32Buffer[2] & 0x00038000UL) >> 15;\r
737             u32Size = (u32CSize + 1UL) * (1UL << (u32Mult + 2UL)) * (1UL << u32RLen);\r
738 \r
739             pSD->diskSize = u32Size / 1024UL;\r
740             pSD->totalSectorN = u32Size / 512UL;\r
741         }\r
742     }\r
743     else\r
744     {\r
745         if(au32Buffer[0] & 0xc0000000UL)\r
746         {\r
747             u32CSize = ((au32Buffer[1] & 0x0000003fUL) << 16) | ((au32Buffer[2] & 0xffff0000UL) >> 16);\r
748             u32Size = (u32CSize + 1UL) * 512UL;  /* Kbytes */\r
749 \r
750             pSD->diskSize = u32Size;\r
751             pSD->totalSectorN = u32Size << 1;\r
752         }\r
753         else\r
754         {\r
755             u32RLen = (au32Buffer[1] & 0x000f0000UL) >> 16;\r
756             u32CSize = ((au32Buffer[1] & 0x000003ffUL) << 2) | ((au32Buffer[2] & 0xc0000000UL) >> 30);\r
757             u32Mult = (au32Buffer[2] & 0x00038000UL) >> 15;\r
758             u32Size = (u32CSize + 1UL) * (1UL << (u32Mult + 2UL)) * (1UL << u32RLen);\r
759 \r
760             pSD->diskSize = u32Size / 1024UL;\r
761             pSD->totalSectorN = u32Size / 512UL;\r
762         }\r
763     }\r
764     pSD->sectorSize = (int)512UL;\r
765 }\r
766 \r
767 /** @endcond HIDDEN_SYMBOLS */\r
768 \r
769 \r
770 /**\r
771  *  @brief  This function use to reset SD function and select card detection source and pin.\r
772  *\r
773  *  @param[in]  sdh    The pointer of the specified SDH module.\r
774  *  @param[in]  u32CardDetSrc   Select card detection pin from GPIO or DAT3 pin. ( \ref CardDetect_From_GPIO / \ref CardDetect_From_DAT3)\r
775  *\r
776  *  @return None\r
777  */\r
778 void SDH_Open(SDH_T *sdh, uint32_t u32CardDetSrc)\r
779 {\r
780     /* enable DMAC */\r
781     sdh->DMACTL = SDH_DMACTL_DMARST_Msk;\r
782     while(sdh->DMACTL & SDH_DMACTL_DMARST_Msk) {}\r
783 \r
784     sdh->DMACTL = SDH_DMACTL_DMAEN_Msk;\r
785 \r
786     /* Reset FMI */\r
787     sdh->GCTL = SDH_GCTL_GCTLRST_Msk | SDH_GCTL_SDEN_Msk;        /* Start reset FMI controller. */\r
788     while(sdh->GCTL & SDH_GCTL_GCTLRST_Msk) {}\r
789 \r
790     memset(&SD0, 0, sizeof(SDH_INFO_T));\r
791 \r
792     /* enable SD */\r
793     sdh->GCTL = SDH_GCTL_SDEN_Msk;\r
794 \r
795     if(u32CardDetSrc & CardDetect_From_DAT3)\r
796     {\r
797         sdh->INTEN &= ~SDH_INTEN_CDSRC_Msk;\r
798     }\r
799     else\r
800     {\r
801         sdh->INTEN |= SDH_INTEN_CDSRC_Msk;\r
802     }\r
803     sdh->INTEN |= SDH_INTEN_CDIEN_Msk;\r
804 \r
805     sdh->CTL |= SDH_CTL_CTLRST_Msk;     /* SD software reset */\r
806     while(sdh->CTL & SDH_CTL_CTLRST_Msk) {}\r
807 \r
808 }\r
809 \r
810 /**\r
811  *  @brief  This function use to initial SD card.\r
812  *\r
813  *  @param[in]    sdh    The pointer of the specified SDH module.\r
814  *\r
815  *  @return None\r
816  *\r
817  *  @details This function is used to initial SD card.\r
818  *           SD initial state needs 400KHz clock output, driver will use HIRC for SD initial clock source.\r
819  *           And then switch back to the user's setting.\r
820  */\r
821 uint32_t SDH_Probe(SDH_T *sdh)\r
822 {\r
823     uint32_t u32Val;\r
824 \r
825     /* Disable FMI/SD host interrupt */\r
826     sdh->GINTEN = 0UL;\r
827 \r
828     sdh->CTL &= ~SDH_CTL_SDNWR_Msk;\r
829     sdh->CTL |=  0x09UL << SDH_CTL_SDNWR_Pos;         /* set SDNWR = 9 */\r
830     sdh->CTL &= ~SDH_CTL_BLKCNT_Msk;\r
831     sdh->CTL |=  0x01UL << SDH_CTL_BLKCNT_Pos;           /* set BLKCNT = 1 */\r
832     sdh->CTL &= ~SDH_CTL_DBW_Msk;               /* SD 1-bit data bus */\r
833 \r
834     if(!(SDH_CardDetection(sdh)))\r
835     {\r
836         return SDH_NO_SD_CARD;\r
837     }\r
838 \r
839     if((u32Val = SDH_Init(sdh)) != 0UL)\r
840     {\r
841         return u32Val;\r
842     }\r
843 \r
844     /* divider */\r
845     if(SD0.CardType == SDH_TYPE_MMC)\r
846     {\r
847         SDH_Set_clock(sdh, MMC_FREQ);\r
848     }\r
849     else\r
850     {\r
851         SDH_Set_clock(sdh, SD_FREQ);\r
852     }\r
853     SDH_Get_SD_info(sdh);\r
854 \r
855     if((u32Val = SDH_SelectCardType(sdh)) != 0UL)\r
856     {\r
857         return u32Val;\r
858     }\r
859 \r
860     SDH_ok = 1;\r
861     return 0UL;\r
862 }\r
863 \r
864 /**\r
865  *  @brief  This function use to read data from SD card.\r
866  *\r
867  *  @param[in]     sdh           The pointer of the specified SDH module.\r
868  *  @param[out]    pu8BufAddr    The buffer to receive the data from SD card.\r
869  *  @param[in]     u32StartSec   The start read sector address.\r
870  *  @param[in]     u32SecCount   The the read sector number of data\r
871  *\r
872  *  @return None\r
873  */\r
874 uint32_t SDH_Read(SDH_T *sdh, uint8_t *pu8BufAddr, uint32_t u32StartSec, uint32_t u32SecCount)\r
875 {\r
876     uint32_t volatile u32IsSendCmd = (uint32_t)FALSE, u32Buf;\r
877     uint32_t volatile u32Reg;\r
878     uint32_t volatile i, u32Loop, u32Status;\r
879     uint32_t u32BlkSize = SDH_BLOCK_SIZE;\r
880 \r
881     SDH_INFO_T *pSD;\r
882 \r
883     /* M2351 is only support SDH0 */\r
884     pSD = &SD0;\r
885 \r
886     /* --- check input parameters */\r
887     if(u32SecCount == 0UL)\r
888     {\r
889         return SDH_SELECT_ERROR;\r
890     }\r
891 \r
892     if((u32Status = SDH_SDCmdAndRsp(sdh, 7UL, pSD->RCA, 0UL)) != Successful)\r
893     {\r
894         return u32Status;\r
895     }\r
896     SDH_CheckRB(sdh);\r
897 \r
898     sdh->BLEN = u32BlkSize - 1UL;       /* the actual byte count is equal to (SDBLEN+1) */\r
899 \r
900     if((pSD->CardType == SDH_TYPE_SD_HIGH) || (pSD->CardType == SDH_TYPE_EMMC))\r
901     {\r
902         sdh->CMDARG = u32StartSec;\r
903     }\r
904     else\r
905     {\r
906         sdh->CMDARG = u32StartSec * u32BlkSize;\r
907     }\r
908 \r
909     sdh->DMASA = (uint32_t)pu8BufAddr;\r
910 \r
911     u32Loop = u32SecCount / 255UL;\r
912     while(u32Loop > 0UL)\r
913     {\r
914         g_u8SDDataReadyFlag = (uint8_t)FALSE;\r
915         u32Reg = sdh->CTL & ~SDH_CTL_CMDCODE_Msk;\r
916         u32Reg = u32Reg | 0xff0000UL;   /* set BLK_CNT to 255 */\r
917         if(u32IsSendCmd == (uint32_t)FALSE)\r
918         {\r
919             sdh->CTL = u32Reg | (18UL << 8) | (SDH_CTL_COEN_Msk | SDH_CTL_RIEN_Msk | SDH_CTL_DIEN_Msk);\r
920             u32IsSendCmd = (uint32_t)TRUE;\r
921         }\r
922         else\r
923         {\r
924             sdh->CTL = u32Reg | SDH_CTL_DIEN_Msk;\r
925         }\r
926 \r
927         while(!g_u8SDDataReadyFlag)\r
928         {\r
929             if(g_u8SDDataReadyFlag)\r
930             {\r
931                 break;\r
932             }\r
933             if(pSD->IsCardInsert == (uint8_t)FALSE)\r
934             {\r
935                 return SDH_NO_SD_CARD;\r
936             }\r
937         }\r
938 \r
939         if(!(sdh->INTSTS & SDH_INTSTS_CRC7_Msk))     /* check CRC7 */\r
940         {\r
941             return SDH_CRC7_ERROR;\r
942         }\r
943 \r
944         if(!(sdh->INTSTS & SDH_INTSTS_CRC16_Msk))    /* check CRC16 */\r
945         {\r
946             return SDH_CRC16_ERROR;\r
947         }\r
948         u32Loop--;\r
949     }\r
950 \r
951     u32Loop = u32SecCount % 255UL;\r
952     if(u32Loop != 0UL)\r
953     {\r
954         uint32_t u32RegTmp;\r
955         g_u8SDDataReadyFlag = (uint8_t)FALSE;\r
956         u32Reg = sdh->CTL & (~SDH_CTL_CMDCODE_Msk);\r
957         u32Reg = u32Reg & (~SDH_CTL_BLKCNT_Msk);\r
958         u32RegTmp = (u32Loop << 16);\r
959         u32Reg |= u32RegTmp;    /* setup SDCR_BLKCNT */\r
960 \r
961         if(u32IsSendCmd == (uint32_t)FALSE)\r
962         {\r
963             sdh->CTL = u32Reg | (18UL << 8) | (SDH_CTL_COEN_Msk | SDH_CTL_RIEN_Msk | SDH_CTL_DIEN_Msk);\r
964             u32IsSendCmd = (uint32_t)TRUE;\r
965         }\r
966         else\r
967         {\r
968             sdh->CTL = u32Reg | SDH_CTL_DIEN_Msk;\r
969         }\r
970 \r
971         while(!g_u8SDDataReadyFlag)\r
972         {\r
973             if(pSD->IsCardInsert == (uint8_t)FALSE)\r
974             {\r
975                 return SDH_NO_SD_CARD;\r
976             }\r
977         }\r
978 \r
979         if(!(sdh->INTSTS & SDH_INTSTS_CRC7_Msk))     /* check CRC7 */\r
980         {\r
981             return SDH_CRC7_ERROR;\r
982         }\r
983 \r
984         if(!(sdh->INTSTS & SDH_INTSTS_CRC16_Msk))     /* check CRC16 */\r
985         {\r
986             return SDH_CRC16_ERROR;\r
987         }\r
988     }\r
989 \r
990     if(SDH_SDCmdAndRsp(sdh, 12UL, 0UL, 0UL))     /* stop command */\r
991     {\r
992         return SDH_CRC7_ERROR;\r
993     }\r
994     SDH_CheckRB(sdh);\r
995 \r
996     SDH_SDCommand(sdh, 7UL, 0UL);\r
997     sdh->CTL |= SDH_CTL_CLK8OEN_Msk;\r
998     while(sdh->CTL & SDH_CTL_CLK8OEN_Msk) {}\r
999 \r
1000     return Successful;\r
1001 }\r
1002 \r
1003 /**\r
1004  *  @brief  This function use to write data to SD card.\r
1005  *\r
1006  *  @param[in]    sdh           The pointer of the specified SDH module.\r
1007  *  @param[in]    pu8BufAddr    The buffer to send the data to SD card.\r
1008  *  @param[in]    u32StartSec   The start write sector address.\r
1009  *  @param[in]    u32SecCount   The the write sector number of data.\r
1010  *\r
1011  *  @return   \ref SDH_SELECT_ERROR : u32SecCount is zero. \n\r
1012  *            \ref SDH_NO_SD_CARD : SD card be removed. \n\r
1013  *            \ref SDH_CRC_ERROR : CRC error happen. \n\r
1014  *            \ref SDH_CRC7_ERROR : CRC7 error happen. \n\r
1015  *            \ref Successful : Write data to SD card success.\r
1016  */\r
1017 uint32_t SDH_Write(SDH_T *sdh, uint8_t *pu8BufAddr, uint32_t u32StartSec, uint32_t u32SecCount)\r
1018 {\r
1019     uint32_t volatile u32IsSendCmd = (uint32_t)FALSE;\r
1020     uint32_t volatile u32Reg;\r
1021     uint32_t volatile i, u32Loop, u32Status;\r
1022 \r
1023     SDH_INFO_T *pSD;\r
1024 \r
1025     /* M2351 is only support SDH0 */\r
1026     pSD = &SD0;\r
1027 \r
1028     /* --- check input parameters */\r
1029     if(u32SecCount == 0UL)\r
1030     {\r
1031         return SDH_SELECT_ERROR;\r
1032     }\r
1033 \r
1034     if((u32Status = SDH_SDCmdAndRsp(sdh, 7UL, pSD->RCA, 0UL)) != Successful)\r
1035     {\r
1036         return u32Status;\r
1037     }\r
1038 \r
1039     SDH_CheckRB(sdh);\r
1040 \r
1041     /* According to SD Spec v2.0, the write CMD block size MUST be 512, and the start address MUST be 512*n. */\r
1042     sdh->BLEN = SDH_BLOCK_SIZE - 1UL;           /* set the block size */\r
1043 \r
1044     if((pSD->CardType == SDH_TYPE_SD_HIGH) || (pSD->CardType == SDH_TYPE_EMMC))\r
1045     {\r
1046         sdh->CMDARG = u32StartSec;\r
1047     }\r
1048     else\r
1049     {\r
1050         sdh->CMDARG = u32StartSec * SDH_BLOCK_SIZE;  /* set start address for SD CMD */\r
1051     }\r
1052 \r
1053     sdh->DMASA = (uint32_t)pu8BufAddr;\r
1054     u32Loop = u32SecCount / 255UL;   /* the maximum block count is 0xFF=255 for register SDCR[BLK_CNT] */\r
1055     while(u32Loop > 0UL)\r
1056     {\r
1057         g_u8SDDataReadyFlag = (uint8_t)FALSE;\r
1058         u32Reg = sdh->CTL & 0xff00c080UL;\r
1059         u32Reg = u32Reg | 0xff0000UL;   /* set BLK_CNT to 0xFF=255 */\r
1060         if(!u32IsSendCmd)\r
1061         {\r
1062             sdh->CTL = u32Reg | (25UL << 8) | (SDH_CTL_COEN_Msk | SDH_CTL_RIEN_Msk | SDH_CTL_DOEN_Msk);\r
1063             u32IsSendCmd = (uint32_t)TRUE;\r
1064         }\r
1065         else\r
1066         {\r
1067             sdh->CTL = u32Reg | SDH_CTL_DOEN_Msk;\r
1068         }\r
1069 \r
1070         while(!g_u8SDDataReadyFlag)\r
1071         {\r
1072             if(pSD->IsCardInsert == (uint8_t)FALSE)\r
1073             {\r
1074                 return SDH_NO_SD_CARD;\r
1075             }\r
1076         }\r
1077 \r
1078         if((sdh->INTSTS & SDH_INTSTS_CRCIF_Msk) != 0UL)      /* check CRC */\r
1079         {\r
1080             sdh->INTSTS = SDH_INTSTS_CRCIF_Msk;\r
1081             return SDH_CRC_ERROR;\r
1082         }\r
1083         u32Loop--;\r
1084     }\r
1085 \r
1086     u32Loop = u32SecCount % 255UL;\r
1087     if(u32Loop != 0UL)\r
1088     {\r
1089         uint32_t u32RegTmp;\r
1090         g_u8SDDataReadyFlag = (uint8_t)FALSE;\r
1091         u32RegTmp = (u32Loop << 16);\r
1092         u32Reg = (sdh->CTL & 0xff00c080UL) | u32RegTmp;\r
1093         if(!u32IsSendCmd)\r
1094         {\r
1095             sdh->CTL = u32Reg | (25UL << 8) | (SDH_CTL_COEN_Msk | SDH_CTL_RIEN_Msk | SDH_CTL_DOEN_Msk);\r
1096             u32IsSendCmd = (uint32_t)TRUE;\r
1097         }\r
1098         else\r
1099         {\r
1100             sdh->CTL = u32Reg | SDH_CTL_DOEN_Msk;\r
1101         }\r
1102 \r
1103         while(!g_u8SDDataReadyFlag)\r
1104         {\r
1105             if(pSD->IsCardInsert == (uint8_t)FALSE)\r
1106             {\r
1107                 return SDH_NO_SD_CARD;\r
1108             }\r
1109         }\r
1110 \r
1111         if((sdh->INTSTS & SDH_INTSTS_CRCIF_Msk) != 0UL)      /* check CRC */\r
1112         {\r
1113             sdh->INTSTS = SDH_INTSTS_CRCIF_Msk;\r
1114             return SDH_CRC_ERROR;\r
1115         }\r
1116     }\r
1117     sdh->INTSTS = SDH_INTSTS_CRCIF_Msk;\r
1118 \r
1119     if(SDH_SDCmdAndRsp(sdh, 12UL, 0UL, 0UL))       /* stop command */\r
1120     {\r
1121         return SDH_CRC7_ERROR;\r
1122     }\r
1123     SDH_CheckRB(sdh);\r
1124 \r
1125     SDH_SDCommand(sdh, 7UL, 0UL);\r
1126     sdh->CTL |= SDH_CTL_CLK8OEN_Msk;\r
1127     while(sdh->CTL & SDH_CTL_CLK8OEN_Msk) {}\r
1128 \r
1129     return Successful;\r
1130 }\r
1131 \r
1132 \r
1133 /*@}*/ /* end of group SDH_EXPORTED_FUNCTIONS */\r
1134 \r
1135 /*@}*/ /* end of group SDH_Driver */\r
1136 \r
1137 /*@}*/ /* end of group Standard_Driver */\r
1138 \r
1139 /*** (C) COPYRIGHT 2017 Nuvoton Technology Corp. ***/\r
1140 \r