SWM341_sdio.c 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877
  1. /******************************************************************************************************************************************
  2. * 文件名称: SWM341_sdio.c
  3. * 功能说明: SWM341单片机的SDIO接口驱动库
  4. * 技术支持: http://www.synwit.com.cn/e/tool/gbook/?bid=1
  5. * 注意事项: 为了通用性、兼容性、易用性,只支持以512字节为单位的读写
  6. * 版本日期: V1.1.0 2017年10月25日
  7. * 升级记录:
  8. *
  9. *
  10. *******************************************************************************************************************************************
  11. * @attention
  12. *
  13. * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS WITH CODING INFORMATION
  14. * REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. AS A RESULT, SYNWIT SHALL NOT BE HELD LIABLE
  15. * FOR ANY DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
  16. * OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION CONTAINED HEREIN IN CONN-
  17. * -ECTION WITH THEIR PRODUCTS.
  18. *
  19. * COPYRIGHT 2012 Synwit Technology
  20. *******************************************************************************************************************************************/
  21. #include "SWM341.h"
  22. #include "SWM341_sdio.h"
  23. SD_CardInfo SD_cardInfo;
  24. /******************************************************************************************************************************************
  25. * 函数名称: SDIO_Init()
  26. * 功能说明: SDIO读写SD卡初始化,初始化成高速4线模式、读写以512字节大小进行
  27. * 输 入: uint32_t freq SDIO_CLK时钟频率
  28. * 输 出: uint32_t SD_RES_OK 操作成功 SD_RES_ERR 操作失败 SD_RES_TIMEOUT 操作超时
  29. * 注意事项: 无
  30. ******************************************************************************************************************************************/
  31. uint32_t SDIO_Init(uint32_t freq)
  32. {
  33. uint32_t res;
  34. uint32_t resp, resps[4];
  35. SYS->CLKSEL &= ~SYS_CLKSEL_SDIO_Msk;
  36. if(SystemCoreClock > 80000000) //SDIO时钟需要小于52MHz
  37. SYS->CLKSEL |= (2 << SYS_CLKSEL_SDIO_Pos); //SDCLK = SYSCLK / 4
  38. else
  39. SYS->CLKSEL |= (0 << SYS_CLKSEL_SDIO_Pos); //SDCLK = SYSCLK / 2
  40. SYS->CLKEN0 |= (0x01 << SYS_CLKEN0_SDIO_Pos);
  41. SDIO->CR2 = (1 << SDIO_CR2_RSTALL_Pos);
  42. SDIO->CR1 = (1 << SDIO_CR1_CDSRC_Pos) |
  43. (0 << SDIO_CR1_8BIT_Pos) |
  44. (0 << SDIO_CR1_4BIT_Pos) |
  45. (1 << SDIO_CR1_PWRON_Pos) |
  46. (7 << SDIO_CR1_VOLT_Pos);
  47. SDIO->CR2 = (1 << SDIO_CR2_CLKEN_Pos) |
  48. (1 << SDIO_CR2_SDCLKEN_Pos) |
  49. (calcSDCLKDiv(100000) << SDIO_CR2_SDCLKDIV_Pos) |
  50. (0xC << SDIO_CR2_TIMEOUT_Pos); // 2**25 SDIO_CLK
  51. while((SDIO->CR2 & SDIO_CR2_CLKRDY_Msk) == 0);
  52. for(int i = 0; i < CyclesPerUs * 10; i++) __NOP();
  53. SDIO->IM = 0xFFFFFFFF;
  54. SDIO_SendCmd(SD_CMD_GO_IDLE_STATE, 0x00, SD_RESP_NO, 0); //CMD0: GO_IDLE_STATE
  55. res = SDIO_SendCmd(SD_CMD_SEND_IF_COND, 0x1AA, SD_RESP_32b, &resp); //CMD8: SEND_IF_COND, 检测工作电压、检测是否支持SD 2.0
  56. if(res != SD_RES_OK)
  57. return res;
  58. if(resp == 0x1AA) SD_cardInfo.CardType = SDIO_STD_CAPACITY_SD_CARD_V2_0;
  59. else SD_cardInfo.CardType = SDIO_STD_CAPACITY_SD_CARD_V1_1;
  60. do //ACMD41: SD_CMD_SD_APP_OP_COND
  61. {
  62. res = SDIO_SendCmd(SD_CMD_APP_CMD, 0x00, SD_RESP_32b, &resp);
  63. if(res != SD_RES_OK)
  64. return res;
  65. if((resp & SD_CS_APP_CMD) == 0) return SD_RES_ERR;
  66. if(SD_cardInfo.CardType == SDIO_STD_CAPACITY_SD_CARD_V2_0)
  67. SDIO_SendCmd(SD_CMD_SD_APP_OP_COND, 0x80100000|0x40000000, SD_RESP_32b, &resp);
  68. else
  69. SDIO_SendCmd(SD_CMD_SD_APP_OP_COND, 0x80100000|0x00000000, SD_RESP_32b, &resp);
  70. } while(((resp >> 31) & 0x01) == 0); //上电没完成时resp[31] == 0
  71. if(((resp >> 30) & 0x01) == 1) SD_cardInfo.CardType = SDIO_HIGH_CAPACITY_SD_CARD;
  72. SDIO_SendCmd(SD_CMD_ALL_SEND_CID, 0x00, SD_RESP_128b, resps); //CMD2: SD_CMD_ALL_SEND_CID,获取CID
  73. parseCID(resps);
  74. SDIO_SendCmd(SD_CMD_SET_REL_ADDR, 0x00, SD_RESP_32b, &resp); //CMD3: SD_CMD_SET_REL_ADDR,设置RCA
  75. SD_cardInfo.RCA = resp >> 16;
  76. SDIO_SendCmd(SD_CMD_SEND_CSD, SD_cardInfo.RCA << 16, SD_RESP_128b, resps); //CMD9: SD_CMD_SEND_CSD,获取CSD
  77. parseCSD(resps);
  78. if(SD_cardInfo.CardBlockSize < 0x200) return SD_RES_ERR; //本驱动只支持以512字节为单位的读写,所以最大读写单位必须不小于512
  79. SDIO->CR2 &= ~(SDIO_CR2_SDCLKEN_Msk | SDIO_CR2_SDCLKDIV_Msk);
  80. SDIO->CR2 |= (1 << SDIO_CR2_SDCLKEN_Pos) |
  81. (calcSDCLKDiv(freq) << SDIO_CR2_SDCLKDIV_Pos); //初始化完成,SDCLK切换到高速
  82. SDIO_SendCmd(SD_CMD_SEL_DESEL_CARD, SD_cardInfo.RCA << 16, SD_RESP_32b_busy, &resp); //CMD7: 选中卡,从Standy模式进入Transfer模式
  83. SDIO->IF = SDIO_IF_TRXDONE_Msk;
  84. SDIO_SendCmd(SD_CMD_APP_CMD, SD_cardInfo.RCA << 16, SD_RESP_32b, &resp);
  85. SDIO_SendCmd(SD_CMD_APP_SD_SET_BUSWIDTH, SD_BUSWIDTH_4b, SD_RESP_32b, &resp); //切换成4位总线模式
  86. SDIO->CR1 |= (1 << SDIO_CR1_4BIT_Pos);
  87. SDIO_SendCmd(SD_CMD_SET_BLOCKLEN, 512, SD_RESP_32b, &resp); //固定块大小位512字节
  88. SD_cardInfo.CardBlockSize = 512;
  89. SDIO->BLK = 512;
  90. return SD_RES_OK;
  91. }
  92. /******************************************************************************************************************************************
  93. * 函数名称: SDIO_BlockWrite()
  94. * 功能说明: 向SD卡写入数据
  95. * 输 入: uint32_t block_addr SD卡块地址,每块512字节
  96. * uint32_t buff[] 要写入的数据
  97. * 输 出: uint32_t SD_RES_OK 操作成功 SD_RES_ERR 操作失败 SD_RES_TIMEOUT 操作超时
  98. * 注意事项: 无
  99. ******************************************************************************************************************************************/
  100. uint32_t SDIO_BlockWrite(uint32_t block_addr, uint32_t buff[])
  101. {
  102. uint32_t res, i;
  103. uint32_t addr, resp;
  104. if(SD_cardInfo.CardType == SDIO_HIGH_CAPACITY_SD_CARD) addr = block_addr;
  105. else addr = block_addr * 512;
  106. res = SDIO_SendCmdWithData(SD_CMD_WRITE_SINGLE_BLOCK, addr, SD_RESP_32b, &resp, 0, 1);
  107. if(res != SD_RES_OK)
  108. return res;
  109. while((SDIO->IF & SDIO_IF_BUFWRRDY_Msk) == 0) __NOP();
  110. SDIO->IF = SDIO_IF_BUFWRRDY_Msk;
  111. for(i = 0; i < 512/4; i++) SDIO->DATA = buff[i];
  112. while((SDIO->IF & SDIO_IF_TRXDONE_Msk) == 0) __NOP();
  113. SDIO->IF = SDIO_IF_TRXDONE_Msk;
  114. return SD_RES_OK;
  115. }
  116. /******************************************************************************************************************************************
  117. * 函数名称: SDIO_MultiBlockWrite()
  118. * 功能说明: 向SD卡写入多块数据
  119. * 输 入: uint32_t block_addr SD卡块地址,每块512字节
  120. * uint16_t block_cnt 要写入的块数
  121. * uint32_t buff[] 要写入的数据
  122. * 输 出: uint32_t SD_RES_OK 操作成功 SD_RES_ERR 操作失败 SD_RES_TIMEOUT 操作超时
  123. * 注意事项: 无
  124. ******************************************************************************************************************************************/
  125. uint32_t SDIO_MultiBlockWrite(uint32_t block_addr, uint16_t block_cnt, uint32_t buff[])
  126. {
  127. uint32_t res, i, j;
  128. uint32_t addr, resp;
  129. if(SD_cardInfo.CardType == SDIO_HIGH_CAPACITY_SD_CARD) addr = block_addr;
  130. else addr = block_addr * 512;
  131. res = SDIO_SendCmdWithData(SD_CMD_WRITE_MULT_BLOCK, addr, SD_RESP_32b, &resp, 0, block_cnt);
  132. if(res != SD_RES_OK)
  133. return res;
  134. for(i = 0; i < block_cnt; i++)
  135. {
  136. while((SDIO->IF & SDIO_IF_BUFWRRDY_Msk) == 0) __NOP();
  137. SDIO->IF = SDIO_IF_BUFWRRDY_Msk;
  138. for(j = 0; j < 512/4; j++) SDIO->DATA = buff[i*(512/4) + j];
  139. }
  140. while((SDIO->IF & SDIO_IF_TRXDONE_Msk) == 0) __NOP();
  141. SDIO->IF = SDIO_IF_TRXDONE_Msk;
  142. return SD_RES_OK;
  143. }
  144. /******************************************************************************************************************************************
  145. * 函数名称: SDIO_DMABlockWrite()
  146. * 功能说明: 通过DMA向SD卡写入多块数据
  147. * 输 入: uint32_t block_addr SD卡块地址,每块512字节
  148. * uint16_t block_cnt 要写入的块数
  149. * uint32_t buff[] 要写入的数据
  150. * 输 出: uint32_t SD_RES_OK 操作成功 SD_RES_ERR 操作失败 SD_RES_TIMEOUT 操作超时
  151. * 注意事项: 无
  152. ******************************************************************************************************************************************/
  153. uint32_t SDIO_DMABlockWrite(uint32_t block_addr, uint16_t block_cnt, uint32_t buff[])
  154. {
  155. uint32_t res;
  156. uint32_t addr, resp;
  157. if(SD_cardInfo.CardType == SDIO_HIGH_CAPACITY_SD_CARD) addr = block_addr;
  158. else addr = block_addr * 512;
  159. SDIO->DMA_MEM_ADDR = (uint32_t) buff;
  160. res = SDIO_SendCmdWithDataByDMA(SD_CMD_WRITE_MULT_BLOCK, addr, SD_RESP_32b, &resp, 0, block_cnt);
  161. if(res != SD_RES_OK)
  162. return res;
  163. while((SDIO->IF & SDIO_IF_TRXDONE_Msk) == 0) __NOP();
  164. SDIO->IF = SDIO_IF_TRXDONE_Msk;
  165. return SD_RES_OK;
  166. }
  167. /******************************************************************************************************************************************
  168. * 函数名称: SDIO_BlockRead()
  169. * 功能说明: 从SD卡读出数据
  170. * 输 入: uint32_t block_addr SD卡块地址,每块512字节
  171. * uint32_t buff[] 读出的数据
  172. * 输 出: uint32_t SD_RES_OK 操作成功 SD_RES_ERR 操作失败 SD_RES_TIMEOUT 操作超时
  173. * 注意事项: 无
  174. ******************************************************************************************************************************************/
  175. uint32_t SDIO_BlockRead(uint32_t block_addr, uint32_t buff[])
  176. {
  177. uint32_t res, i;
  178. uint32_t addr, resp;
  179. if(SD_cardInfo.CardType == SDIO_HIGH_CAPACITY_SD_CARD) addr = block_addr;
  180. else addr = block_addr * 512;
  181. res = SDIO_SendCmdWithData(SD_CMD_READ_SINGLE_BLOCK, addr, SD_RESP_32b, &resp, 1, 1);
  182. if(res != SD_RES_OK)
  183. return res;
  184. while((SDIO->IF & SDIO_IF_BUFRDRDY_Msk) == 0) __NOP();
  185. SDIO->IF = SDIO_IF_BUFRDRDY_Msk;
  186. for(i = 0; i < 512/4; i++) buff[i] = SDIO->DATA;
  187. while((SDIO->IF & SDIO_IF_TRXDONE_Msk) == 0) __NOP();
  188. SDIO->IF = SDIO_IF_TRXDONE_Msk;
  189. return SD_RES_OK;
  190. }
  191. /******************************************************************************************************************************************
  192. * 函数名称: SDIO_MultiBlockRead()
  193. * 功能说明: 从SD卡读出多块数据
  194. * 输 入: uint32_t block_addr SD卡块地址,每块512字节
  195. * uint16_t block_cnt 要读出的块数
  196. * uint32_t buff[] 读出的数据
  197. * 输 出: uint32_t SD_RES_OK 操作成功 SD_RES_ERR 操作失败 SD_RES_TIMEOUT 操作超时
  198. * 注意事项: 无
  199. ******************************************************************************************************************************************/
  200. uint32_t SDIO_MultiBlockRead(uint32_t block_addr, uint16_t block_cnt, uint32_t buff[])
  201. {
  202. uint32_t res, i, j;
  203. uint32_t addr, resp;
  204. if(SD_cardInfo.CardType == SDIO_HIGH_CAPACITY_SD_CARD) addr = block_addr;
  205. else addr = block_addr * 512;
  206. res = SDIO_SendCmdWithData(SD_CMD_READ_MULT_BLOCK, addr, SD_RESP_32b, &resp, 1, block_cnt);
  207. if(res != SD_RES_OK)
  208. return res;
  209. for(i = 0; i < block_cnt; i++)
  210. {
  211. while((SDIO->IF & SDIO_IF_BUFRDRDY_Msk) == 0) __NOP();
  212. SDIO->IF = SDIO_IF_BUFRDRDY_Msk;
  213. for(j = 0; j < 512/4; j++) buff[i*(512/4) + j] = SDIO->DATA;
  214. }
  215. while((SDIO->IF & SDIO_IF_TRXDONE_Msk) == 0) __NOP();
  216. SDIO->IF = SDIO_IF_TRXDONE_Msk;
  217. return SD_RES_OK;
  218. }
  219. /******************************************************************************************************************************************
  220. * 函数名称: SDIO_DMABlockRead()
  221. * 功能说明: 通过DMA从SD卡读出多块数据
  222. * 输 入: uint32_t block_addr SD卡块地址,每块512字节
  223. * uint16_t block_cnt 要读出的块数
  224. * uint32_t buff[] 读出的数据
  225. * 输 出: uint32_t SD_RES_OK 操作成功 SD_RES_ERR 操作失败 SD_RES_TIMEOUT 操作超时
  226. * 注意事项: 无
  227. ******************************************************************************************************************************************/
  228. uint32_t SDIO_DMABlockRead(uint32_t block_addr, uint16_t block_cnt, uint32_t buff[])
  229. {
  230. uint32_t res;
  231. uint32_t addr, resp;
  232. if(SD_cardInfo.CardType == SDIO_HIGH_CAPACITY_SD_CARD) addr = block_addr;
  233. else addr = block_addr * 512;
  234. SDIO->DMA_MEM_ADDR = (uint32_t)buff;
  235. res = SDIO_SendCmdWithDataByDMA(SD_CMD_READ_MULT_BLOCK, addr, SD_RESP_32b, &resp, 1, block_cnt);
  236. if(res != SD_RES_OK)
  237. return res;
  238. while((SDIO->IF & SDIO_IF_TRXDONE_Msk) == 0) __NOP();
  239. SDIO->IF = SDIO_IF_TRXDONE_Msk;
  240. return SD_RES_OK;
  241. }
  242. /******************************************************************************************************************************************
  243. * 函数名称: _SDIO_SendCmd()
  244. * 功能说明: SDIO向SD卡发送命令
  245. * 输 入: uint32_t cmd 命令索引
  246. * uint32_t arg 命令参数
  247. * uint32_t resp_type 响应类型,取值SD_RESP_NO、SD_RESP_32b、SD_RESP_128b、SD_RESP_32b_busy
  248. * uint32_t *resp_data 响应内容
  249. * uint32_t have_data 是否有数据传输
  250. * uint32_t data_read 1 读SD卡 0 写SD卡
  251. * uint16_t block_cnt 读写块个数
  252. * uint32_t use_dma 1 使用DMA搬运数据
  253. * 输 出: uint32_t SD_RES_OK 操作成功 SD_RES_ERR 操作失败 SD_RES_TIMEOUT 操作超时
  254. * 注意事项: 无
  255. ******************************************************************************************************************************************/
  256. uint32_t _SDIO_SendCmd(uint32_t cmd, uint32_t arg, uint32_t resp_type, uint32_t *resp_data, uint32_t have_data, uint32_t data_read, uint16_t block_cnt, uint32_t use_dma)
  257. {
  258. SDIO->BLK &= ~SDIO_BLK_COUNT_Msk;
  259. SDIO->BLK |= (block_cnt << SDIO_BLK_COUNT_Pos);
  260. SDIO->ARG = arg;
  261. SDIO->CMD = (cmd << SDIO_CMD_CMDINDX_Pos) |
  262. (0 << SDIO_CMD_CMDTYPE_Pos) |
  263. (0 << SDIO_CMD_IDXCHECK_Pos) |
  264. (0 << SDIO_CMD_CRCCHECK_Pos) |
  265. (resp_type << SDIO_CMD_RESPTYPE_Pos) |
  266. (have_data << SDIO_CMD_HAVEDATA_Pos) |
  267. (data_read << SDIO_CMD_DIRREAD_Pos) |
  268. ((block_cnt > 1) << SDIO_CMD_MULTBLK_Pos) |
  269. ((block_cnt > 1) << SDIO_CMD_BLKCNTEN_Pos) |
  270. (((cmd == 53) ? 0 : (block_cnt > 1)) << SDIO_CMD_AUTOCMD12_Pos) |
  271. (use_dma << SDIO_CMD_DMAEN_Pos);
  272. while((SDIO->IF & SDIO_IF_CMDDONE_Msk) == 0)
  273. {
  274. if(SDIO->IF & SDIO_IF_CMDTIMEOUT_Msk)
  275. {
  276. SDIO->IF = SDIO_IF_CMDTIMEOUT_Msk;
  277. return SD_RES_TIMEOUT;
  278. }
  279. else if(SDIO->IF & SDIO_IF_ERROR_Msk)
  280. {
  281. SDIO->IF = 0xFFFFFFFF;
  282. return SD_RES_ERR;
  283. }
  284. }
  285. SDIO->IF = SDIO_IF_CMDDONE_Msk;
  286. if(resp_type == SD_RESP_32b)
  287. {
  288. resp_data[0] = SDIO->RESP[0];
  289. }
  290. else if(resp_type == SD_RESP_128b)
  291. {
  292. //寄存器中将CID/CSD[127-8]依次存放在了RESP3-0[119-0],最低位的CRC被丢掉
  293. //读出数据时调整了顺序,将CID/CSD[127-8]存放在resp_data0-3[127-8],最低8位填充0x00
  294. resp_data[0] = (SDIO->RESP[3] << 8) + ((SDIO->RESP[2] >> 24) & 0xFF);
  295. resp_data[1] = (SDIO->RESP[2] << 8) + ((SDIO->RESP[1] >> 24) & 0xFF);
  296. resp_data[2] = (SDIO->RESP[1] << 8) + ((SDIO->RESP[0] >> 24) & 0xFF);
  297. resp_data[3] = (SDIO->RESP[0] << 8) + 0x00;
  298. }
  299. return SD_RES_OK;
  300. }
  301. void parseCID(uint32_t CID_Tab[4])
  302. {
  303. uint8_t tmp = 0;
  304. /*!< Byte 0 */
  305. tmp = (uint8_t)((CID_Tab[0] & 0xFF000000) >> 24);
  306. SD_cardInfo.SD_cid.ManufacturerID = tmp;
  307. /*!< Byte 1 */
  308. tmp = (uint8_t)((CID_Tab[0] & 0x00FF0000) >> 16);
  309. SD_cardInfo.SD_cid.OEM_AppliID = tmp << 8;
  310. /*!< Byte 2 */
  311. tmp = (uint8_t)((CID_Tab[0] & 0x000000FF00) >> 8);
  312. SD_cardInfo.SD_cid.OEM_AppliID |= tmp;
  313. /*!< Byte 3 */
  314. tmp = (uint8_t)(CID_Tab[0] & 0x000000FF);
  315. SD_cardInfo.SD_cid.ProdName1 = tmp << 24;
  316. /*!< Byte 4 */
  317. tmp = (uint8_t)((CID_Tab[1] & 0xFF000000) >> 24);
  318. SD_cardInfo.SD_cid.ProdName1 |= tmp << 16;
  319. /*!< Byte 5 */
  320. tmp = (uint8_t)((CID_Tab[1] & 0x00FF0000) >> 16);
  321. SD_cardInfo.SD_cid.ProdName1 |= tmp << 8;
  322. /*!< Byte 6 */
  323. tmp = (uint8_t)((CID_Tab[1] & 0x0000FF00) >> 8);
  324. SD_cardInfo.SD_cid.ProdName1 |= tmp;
  325. /*!< Byte 7 */
  326. tmp = (uint8_t)(CID_Tab[1] & 0x000000FF);
  327. SD_cardInfo.SD_cid.ProdName2 = tmp;
  328. /*!< Byte 8 */
  329. tmp = (uint8_t)((CID_Tab[2] & 0xFF000000) >> 24);
  330. SD_cardInfo.SD_cid.ProdRev = tmp;
  331. /*!< Byte 9 */
  332. tmp = (uint8_t)((CID_Tab[2] & 0x00FF0000) >> 16);
  333. SD_cardInfo.SD_cid.ProdSN = tmp << 24;
  334. /*!< Byte 10 */
  335. tmp = (uint8_t)((CID_Tab[2] & 0x0000FF00) >> 8);
  336. SD_cardInfo.SD_cid.ProdSN |= tmp << 16;
  337. /*!< Byte 11 */
  338. tmp = (uint8_t)(CID_Tab[2] & 0x000000FF);
  339. SD_cardInfo.SD_cid.ProdSN |= tmp << 8;
  340. /*!< Byte 12 */
  341. tmp = (uint8_t)((CID_Tab[3] & 0xFF000000) >> 24);
  342. SD_cardInfo.SD_cid.ProdSN |= tmp;
  343. /*!< Byte 13 */
  344. tmp = (uint8_t)((CID_Tab[3] & 0x00FF0000) >> 16);
  345. SD_cardInfo.SD_cid.Reserved1 |= (tmp & 0xF0) >> 4;
  346. SD_cardInfo.SD_cid.ManufactDate = (tmp & 0x0F) << 8;
  347. /*!< Byte 14 */
  348. tmp = (uint8_t)((CID_Tab[3] & 0x0000FF00) >> 8);
  349. SD_cardInfo.SD_cid.ManufactDate |= tmp;
  350. }
  351. void parseCSD(uint32_t CSD_Tab[4])
  352. {
  353. uint8_t tmp = 0;
  354. /*!< Byte 0 */
  355. tmp = (uint8_t)((CSD_Tab[0] & 0xFF000000) >> 24);
  356. SD_cardInfo.SD_csd.CSDStruct = (tmp & 0xC0) >> 6;
  357. SD_cardInfo.SD_csd.SysSpecVersion = (tmp & 0x3C) >> 2;
  358. SD_cardInfo.SD_csd.Reserved1 = tmp & 0x03;
  359. /*!< Byte 1 */
  360. tmp = (uint8_t)((CSD_Tab[0] & 0x00FF0000) >> 16);
  361. SD_cardInfo.SD_csd.TAAC = tmp;
  362. /*!< Byte 2 */
  363. tmp = (uint8_t)((CSD_Tab[0] & 0x0000FF00) >> 8);
  364. SD_cardInfo.SD_csd.NSAC = tmp;
  365. /*!< Byte 3 */
  366. tmp = (uint8_t)(CSD_Tab[0] & 0x000000FF);
  367. SD_cardInfo.SD_csd.MaxBusClkFrec = tmp;
  368. /*!< Byte 4 */
  369. tmp = (uint8_t)((CSD_Tab[1] & 0xFF000000) >> 24);
  370. SD_cardInfo.SD_csd.CardComdClasses = tmp << 4;
  371. /*!< Byte 5 */
  372. tmp = (uint8_t)((CSD_Tab[1] & 0x00FF0000) >> 16);
  373. SD_cardInfo.SD_csd.CardComdClasses |= (tmp & 0xF0) >> 4;
  374. SD_cardInfo.SD_csd.RdBlockLen = tmp & 0x0F;
  375. /*!< Byte 6 */
  376. tmp = (uint8_t)((CSD_Tab[1] & 0x0000FF00) >> 8);
  377. SD_cardInfo.SD_csd.PartBlockRead = (tmp & 0x80) >> 7;
  378. SD_cardInfo.SD_csd.WrBlockMisalign = (tmp & 0x40) >> 6;
  379. SD_cardInfo.SD_csd.RdBlockMisalign = (tmp & 0x20) >> 5;
  380. SD_cardInfo.SD_csd.DSRImpl = (tmp & 0x10) >> 4;
  381. SD_cardInfo.SD_csd.Reserved2 = 0; /*!< Reserved */
  382. if ((SD_cardInfo.CardType == SDIO_STD_CAPACITY_SD_CARD_V1_1) ||
  383. (SD_cardInfo.CardType == SDIO_STD_CAPACITY_SD_CARD_V2_0))
  384. {
  385. SD_cardInfo.SD_csd.DeviceSize = (tmp & 0x03) << 10;
  386. /*!< Byte 7 */
  387. tmp = (uint8_t)(CSD_Tab[1] & 0x000000FF);
  388. SD_cardInfo.SD_csd.DeviceSize |= (tmp) << 2;
  389. /*!< Byte 8 */
  390. tmp = (uint8_t)((CSD_Tab[2] & 0xFF000000) >> 24);
  391. SD_cardInfo.SD_csd.DeviceSize |= (tmp & 0xC0) >> 6;
  392. SD_cardInfo.SD_csd.MaxRdCurrentVDDMin = (tmp & 0x38) >> 3;
  393. SD_cardInfo.SD_csd.MaxRdCurrentVDDMax = (tmp & 0x07);
  394. /*!< Byte 9 */
  395. tmp = (uint8_t)((CSD_Tab[2] & 0x00FF0000) >> 16);
  396. SD_cardInfo.SD_csd.MaxWrCurrentVDDMin = (tmp & 0xE0) >> 5;
  397. SD_cardInfo.SD_csd.MaxWrCurrentVDDMax = (tmp & 0x1C) >> 2;
  398. SD_cardInfo.SD_csd.DeviceSizeMul = (tmp & 0x03) << 1;
  399. /*!< Byte 10 */
  400. tmp = (uint8_t)((CSD_Tab[2] & 0x0000FF00) >> 8);
  401. SD_cardInfo.SD_csd.DeviceSizeMul |= (tmp & 0x80) >> 7;
  402. SD_cardInfo.CardCapacity = (SD_cardInfo.SD_csd.DeviceSize + 1) ;
  403. SD_cardInfo.CardCapacity *= (1 << (SD_cardInfo.SD_csd.DeviceSizeMul + 2));
  404. SD_cardInfo.CardBlockSize = 1 << (SD_cardInfo.SD_csd.RdBlockLen);
  405. SD_cardInfo.CardCapacity *= SD_cardInfo.CardBlockSize;
  406. }
  407. else if (SD_cardInfo.CardType == SDIO_HIGH_CAPACITY_SD_CARD)
  408. {
  409. /*!< Byte 7 */
  410. tmp = (uint8_t)(CSD_Tab[1] & 0x000000FF);
  411. SD_cardInfo.SD_csd.DeviceSize = (tmp & 0x3F) << 16;
  412. /*!< Byte 8 */
  413. tmp = (uint8_t)((CSD_Tab[2] & 0xFF000000) >> 24);
  414. SD_cardInfo.SD_csd.DeviceSize |= (tmp << 8);
  415. /*!< Byte 9 */
  416. tmp = (uint8_t)((CSD_Tab[2] & 0x00FF0000) >> 16);
  417. SD_cardInfo.SD_csd.DeviceSize |= (tmp);
  418. /*!< Byte 10 */
  419. tmp = (uint8_t)((CSD_Tab[2] & 0x0000FF00) >> 8);
  420. SD_cardInfo.CardCapacity = (uint64_t)(SD_cardInfo.SD_csd.DeviceSize + 1) * 512 * 1024;
  421. SD_cardInfo.CardBlockSize = 512;
  422. }
  423. SD_cardInfo.SD_csd.EraseGrSize = (tmp & 0x40) >> 6;
  424. SD_cardInfo.SD_csd.EraseGrMul = (tmp & 0x3F) << 1;
  425. /*!< Byte 11 */
  426. tmp = (uint8_t)(CSD_Tab[2] & 0x000000FF);
  427. SD_cardInfo.SD_csd.EraseGrMul |= (tmp & 0x80) >> 7;
  428. SD_cardInfo.SD_csd.WrProtectGrSize = (tmp & 0x7F);
  429. /*!< Byte 12 */
  430. tmp = (uint8_t)((CSD_Tab[3] & 0xFF000000) >> 24);
  431. SD_cardInfo.SD_csd.WrProtectGrEnable = (tmp & 0x80) >> 7;
  432. SD_cardInfo.SD_csd.ManDeflECC = (tmp & 0x60) >> 5;
  433. SD_cardInfo.SD_csd.WrSpeedFact = (tmp & 0x1C) >> 2;
  434. SD_cardInfo.SD_csd.MaxWrBlockLen = (tmp & 0x03) << 2;
  435. /*!< Byte 13 */
  436. tmp = (uint8_t)((CSD_Tab[3] & 0x00FF0000) >> 16);
  437. SD_cardInfo.SD_csd.MaxWrBlockLen |= (tmp & 0xC0) >> 6;
  438. SD_cardInfo.SD_csd.WriteBlockPaPartial = (tmp & 0x20) >> 5;
  439. SD_cardInfo.SD_csd.Reserved3 = 0;
  440. SD_cardInfo.SD_csd.ContentProtectAppli = (tmp & 0x01);
  441. /*!< Byte 14 */
  442. tmp = (uint8_t)((CSD_Tab[3] & 0x0000FF00) >> 8);
  443. SD_cardInfo.SD_csd.FileFormatGrouop = (tmp & 0x80) >> 7;
  444. SD_cardInfo.SD_csd.CopyFlag = (tmp & 0x40) >> 6;
  445. SD_cardInfo.SD_csd.PermWrProtect = (tmp & 0x20) >> 5;
  446. SD_cardInfo.SD_csd.TempWrProtect = (tmp & 0x10) >> 4;
  447. SD_cardInfo.SD_csd.FileFormat = (tmp & 0x0C) >> 2;
  448. SD_cardInfo.SD_csd.ECC = (tmp & 0x03);
  449. }
  450. uint32_t calcSDCLKDiv(uint32_t freq)
  451. {
  452. uint32_t prediv;
  453. switch((SYS->CLKSEL & SYS_CLKSEL_SDIO_Msk) >> SYS_CLKSEL_SDIO_Pos)
  454. {
  455. case 0: prediv = 1; break;
  456. case 1: prediv = 3; break;
  457. case 2: prediv = 2; break;
  458. case 3: prediv = 0; break;
  459. }
  460. uint32_t clkdiv = (SystemCoreClock / (1 << prediv)) / freq;
  461. uint32_t regdiv = 0;
  462. if(clkdiv > 128) regdiv = 0x80;
  463. else if(clkdiv > 64) regdiv = 0x40;
  464. else if(clkdiv > 32) regdiv = 0x20;
  465. else if(clkdiv > 16) regdiv = 0x10;
  466. else if(clkdiv > 8) regdiv = 0x08;
  467. else if(clkdiv > 4) regdiv = 0x04;
  468. else if(clkdiv > 2) regdiv = 0x02;
  469. else if(clkdiv > 1) regdiv = 0x01;
  470. else regdiv = 0x00;
  471. return regdiv;
  472. }
  473. /******************************************************************************************************************************************
  474. * 函数名称: SDIO_IO_Init()
  475. * 功能说明: SDIO读写IO卡初始化
  476. * 输 入: uint32_t freq SDIO_CLK时钟频率
  477. * enum SDIO_bus_width w SDIO_1bit 1-bit bus SDIO_4bit 4-bit bus
  478. * 输 出: uint32_t SD_RES_OK 操作成功 SD_RES_ERR 操作失败 SD_RES_TIMEOUT 操作超时
  479. * 注意事项: 无
  480. ******************************************************************************************************************************************/
  481. uint32_t SDIO_IO_Init(uint32_t freq, enum SDIO_bus_width w)
  482. {
  483. uint32_t res;
  484. uint32_t resp, resps[4];
  485. SYS->CLKSEL &= ~SYS_CLKSEL_SDIO_Msk;
  486. if(SystemCoreClock > 80000000) //SDIO时钟需要小于52MHz
  487. SYS->CLKSEL |= (2 << SYS_CLKSEL_SDIO_Pos); //SDCLK = SYSCLK / 4
  488. else
  489. SYS->CLKSEL |= (0 << SYS_CLKSEL_SDIO_Pos); //SDCLK = SYSCLK / 2
  490. SYS->CLKEN0 |= (0x01 << SYS_CLKEN0_SDIO_Pos);
  491. // SDIO->CR2 = (1 << SDIO_CR2_RSTALL_Pos);
  492. for(int i = 0; i < CyclesPerUs; i++) __NOP();
  493. SDIO->CR1 = (1 << SDIO_CR1_CDSRC_Pos) |
  494. (0 << SDIO_CR1_8BIT_Pos) |
  495. (w << SDIO_CR1_4BIT_Pos) |
  496. (1 << SDIO_CR1_PWRON_Pos) |
  497. (7 << SDIO_CR1_VOLT_Pos);
  498. SDIO->CR2 = (1 << SDIO_CR2_CLKEN_Pos) |
  499. (1 << SDIO_CR2_SDCLKEN_Pos) |
  500. (calcSDCLKDiv(freq) << SDIO_CR2_SDCLKDIV_Pos) |
  501. (0xC << SDIO_CR2_TIMEOUT_Pos); // 2**25 SDIO_CLK
  502. while((SDIO->CR2 & SDIO_CR2_CLKRDY_Msk) == 0);
  503. for(int i = 0; i < CyclesPerUs * 10; i++) __NOP();
  504. SDIO->IM = 0xFFFFFFFF;
  505. return SD_RES_OK;
  506. }
  507. /******************************************************************************************************************************************
  508. * 函数名称: SDIO_IO_ByteWrite()
  509. * 功能说明: 向IO卡写入单个字节
  510. * 输 入: uint8_t func The number of the function within the I/O card you wish to read or write
  511. * uint32_t addr Start Address of I/O register to read or write. Range is 0--0x1FFFF
  512. * uint32_t buff[] 要写出的数据
  513. * uint16_t block_size 要写出的字节个数,取值 1--512
  514. * 输 出: uint32_t SD_RES_OK 操作成功 SD_RES_ERR 操作失败 SD_RES_TIMEOUT 操作超时
  515. * 注意事项: 无
  516. ******************************************************************************************************************************************/
  517. uint32_t SDIO_IO_ByteWrite(uint8_t func, uint32_t addr, uint8_t data)
  518. {
  519. uint32_t res;
  520. uint32_t arg, resp;
  521. arg = (1u << SD_CMD53_ARG_nRW) |
  522. (func << SD_CMD53_ARG_Function) |
  523. (addr << SD_CMD53_ARG_Addr) | data;
  524. res = SDIO_SendCmd(52, arg, SD_RESP_32b, &resp);
  525. if(res != SD_RES_OK)
  526. return res;
  527. return SD_RES_OK;
  528. }
  529. /******************************************************************************************************************************************
  530. * 函数名称: SDIO_IO_ByteRead()
  531. * 功能说明: 从IO卡读出单个字节
  532. * 输 入: uint8_t func The number of the function within the I/O card you wish to read or write
  533. * uint32_t addr Start Address of I/O register to read or write. Range is 0--0x1FFFF
  534. * uint32_t buff[] 读取到的数据存入此数组
  535. * uint16_t block_size 要读取的字节个数,取值 1--512
  536. * 输 出: uint32_t SD_RES_OK 操作成功 SD_RES_ERR 操作失败 SD_RES_TIMEOUT 操作超时
  537. * 注意事项: 无
  538. ******************************************************************************************************************************************/
  539. uint32_t SDIO_IO_ByteRead(uint8_t func, uint32_t addr, uint8_t * data)
  540. {
  541. uint32_t res;
  542. uint32_t arg, resp;
  543. arg = (0u << SD_CMD53_ARG_nRW) |
  544. (func << SD_CMD53_ARG_Function) |
  545. (addr << SD_CMD53_ARG_Addr) | 0x00;
  546. res = SDIO_SendCmd(52, arg, SD_RESP_32b, &resp);
  547. if(res != SD_RES_OK)
  548. return res;
  549. *data = resp & 0xFF;
  550. return SD_RES_OK;
  551. }
  552. /******************************************************************************************************************************************
  553. * 函数名称: SDIO_IO_BlockWrite()
  554. * 功能说明: 向IO卡写入单个块数据
  555. * 输 入: uint8_t func The number of the function within the I/O card you wish to read or write
  556. * uint32_t addr Start Address of I/O register to read or write. Range is 0--0x1FFFF
  557. * uint8_t addrInc 0 Multi byte R/W to fixed address 1 Multi byte R/W to incrementing address
  558. * uint32_t buff[] 要写出的数据
  559. * uint16_t block_size 要写出的字节个数,取值 1--512
  560. * 输 出: uint32_t SD_RES_OK 操作成功 SD_RES_ERR 操作失败 SD_RES_TIMEOUT 操作超时
  561. * 注意事项: 无
  562. ******************************************************************************************************************************************/
  563. uint32_t SDIO_IO_BlockWrite(uint8_t func, uint32_t addr, uint8_t addrInc, uint32_t buff[], uint16_t block_size)
  564. {
  565. uint32_t res, i;
  566. uint32_t arg, resp;
  567. SDIO->BLK = block_size;
  568. arg = (1u << SD_CMD53_ARG_nRW) |
  569. (func << SD_CMD53_ARG_Function) |
  570. (addr << SD_CMD53_ARG_Addr) |
  571. (addrInc << SD_CMD53_ARG_AddrInc) |
  572. ((block_size % 512) << SD_CMD53_ARG_Count) |
  573. (0 << SD_CMD53_ARG_CountUnit);
  574. res = SDIO_SendCmdWithData(53, arg, SD_RESP_32b, &resp, 0, 1);
  575. if(res != SD_RES_OK)
  576. return res;
  577. while((SDIO->IF & SDIO_IF_BUFWRRDY_Msk) == 0) __NOP();
  578. SDIO->IF = SDIO_IF_BUFWRRDY_Msk;
  579. for(i = 0; i < block_size/4; i++) SDIO->DATA = buff[i];
  580. while((SDIO->IF & SDIO_IF_TRXDONE_Msk) == 0) __NOP();
  581. SDIO->IF = SDIO_IF_TRXDONE_Msk;
  582. return SD_RES_OK;
  583. }
  584. /******************************************************************************************************************************************
  585. * 函数名称: SDIO_IO_BlockRead()
  586. * 功能说明: 从IO卡读出单个块数据
  587. * 输 入: uint8_t func The number of the function within the I/O card you wish to read or write
  588. * uint32_t addr Start Address of I/O register to read or write. Range is 0--0x1FFFF
  589. * uint8_t addrInc 0 Multi byte R/W to fixed address 1 Multi byte R/W to incrementing address
  590. * uint32_t buff[] 读取到的数据存入此数组
  591. * uint16_t block_size 要读取的字节个数,取值 1--512
  592. * 输 出: uint32_t SD_RES_OK 操作成功 SD_RES_ERR 操作失败 SD_RES_TIMEOUT 操作超时
  593. * 注意事项: 无
  594. ******************************************************************************************************************************************/
  595. uint32_t SDIO_IO_BlockRead(uint8_t func, uint32_t addr, uint8_t addrInc, uint32_t buff[], uint16_t block_size)
  596. {
  597. uint32_t res, i;
  598. uint32_t arg, resp;
  599. SDIO->BLK = block_size;
  600. arg = (0u << SD_CMD53_ARG_nRW) |
  601. (func << SD_CMD53_ARG_Function) |
  602. (addr << SD_CMD53_ARG_Addr) |
  603. (addrInc << SD_CMD53_ARG_AddrInc) |
  604. ((block_size % 512) << SD_CMD53_ARG_Count) |
  605. (0 << SD_CMD53_ARG_CountUnit);
  606. res = SDIO_SendCmdWithData(53, arg, SD_RESP_32b, &resp, 1, 1);
  607. if(res != SD_RES_OK)
  608. return res;
  609. while((SDIO->IF & SDIO_IF_BUFRDRDY_Msk) == 0) __NOP();
  610. SDIO->IF = SDIO_IF_BUFRDRDY_Msk;
  611. for(i = 0; i < block_size/4; i++) buff[i] = SDIO->DATA;
  612. while((SDIO->IF & SDIO_IF_TRXDONE_Msk) == 0) __NOP();
  613. SDIO->IF = SDIO_IF_TRXDONE_Msk;
  614. return SD_RES_OK;
  615. }
  616. /******************************************************************************************************************************************
  617. * 函数名称: SDIO_IO_MultiBlockWrite()
  618. * 功能说明: 向IO卡写入多个块数据
  619. * 输 入: uint8_t func The number of the function within the I/O card you wish to read or write
  620. * uint32_t addr Start Address of I/O register to read or write. Range is 0--0x1FFFF
  621. * uint8_t addrInc 0 Multi byte R/W to fixed address 1 Multi byte R/W to incrementing address
  622. * uint32_t buff[] 要写出的数据
  623. * uint16_t block_count 要写出的块个数,块大小为 512 字节
  624. * 输 出: uint32_t SD_RES_OK 操作成功 SD_RES_ERR 操作失败 SD_RES_TIMEOUT 操作超时
  625. * 注意事项: 无
  626. ******************************************************************************************************************************************/
  627. uint32_t SDIO_IO_MultiBlockWrite(uint8_t func, uint32_t addr, uint8_t addrInc, uint32_t buff[], uint16_t block_count)
  628. {
  629. uint32_t res, i, j;
  630. uint32_t arg, resp;
  631. SDIO->BLK = 512;
  632. arg = (1u << SD_CMD53_ARG_nRW) |
  633. (func << SD_CMD53_ARG_Function) |
  634. (addr << SD_CMD53_ARG_Addr) |
  635. (addrInc << SD_CMD53_ARG_AddrInc) |
  636. (block_count << SD_CMD53_ARG_Count) |
  637. (1 << SD_CMD53_ARG_CountUnit);
  638. res = SDIO_SendCmdWithData(53, arg, SD_RESP_32b, &resp, 0, block_count);
  639. if(res != SD_RES_OK)
  640. return res;
  641. for(i = 0; i < block_count; i++)
  642. {
  643. while((SDIO->IF & SDIO_IF_BUFWRRDY_Msk) == 0) __NOP();
  644. SDIO->IF = SDIO_IF_BUFWRRDY_Msk;
  645. for(j = 0; j < 512/4; j++) SDIO->DATA = buff[i*(512/4) + j];
  646. }
  647. while((SDIO->IF & SDIO_IF_TRXDONE_Msk) == 0) __NOP();
  648. SDIO->IF = SDIO_IF_TRXDONE_Msk;
  649. return SD_RES_OK;
  650. }
  651. /******************************************************************************************************************************************
  652. * 函数名称: SDIO_IO_MultiBlockRead()
  653. * 功能说明: 从IO卡读出多个块数据
  654. * 输 入: uint8_t func The number of the function within the I/O card you wish to read or write
  655. * uint32_t addr Start Address of I/O register to read or write. Range is 0--0x1FFFF
  656. * uint8_t addrInc 0 Multi byte R/W to fixed address 1 Multi byte R/W to incrementing address
  657. * uint32_t buff[] 读取到的数据存入此数组
  658. * uint16_t block_count 要读取的块个数,块大小为 512 字节
  659. * 输 出: uint32_t SD_RES_OK 操作成功 SD_RES_ERR 操作失败 SD_RES_TIMEOUT 操作超时
  660. * 注意事项: 无
  661. ******************************************************************************************************************************************/
  662. uint32_t SDIO_IO_MultiBlockRead(uint8_t func, uint32_t addr, uint8_t addrInc, uint32_t buff[], uint16_t block_count)
  663. {
  664. uint32_t res, i, j;
  665. uint32_t arg, resp;
  666. SDIO->BLK = 512;
  667. arg = (0u << SD_CMD53_ARG_nRW) |
  668. (func << SD_CMD53_ARG_Function) |
  669. (addr << SD_CMD53_ARG_Addr) |
  670. (addrInc << SD_CMD53_ARG_AddrInc) |
  671. (block_count << SD_CMD53_ARG_Count) |
  672. (1 << SD_CMD53_ARG_CountUnit);
  673. res = SDIO_SendCmdWithData(53, arg, SD_RESP_32b, &resp, 1, block_count);
  674. if(res != SD_RES_OK)
  675. return res;
  676. for(i = 0; i < block_count; i++)
  677. {
  678. while((SDIO->IF & SDIO_IF_BUFRDRDY_Msk) == 0) __NOP();
  679. SDIO->IF = SDIO_IF_BUFRDRDY_Msk;
  680. for(j = 0; j < 512/4; j++) buff[i*(512/4) + j] = SDIO->DATA;
  681. }
  682. while((SDIO->IF & SDIO_IF_TRXDONE_Msk) == 0) __NOP();
  683. SDIO->IF = SDIO_IF_TRXDONE_Msk;
  684. return SD_RES_OK;
  685. }