sdcmd.c
上传用户:yj_qqy
上传日期:2017-01-28
资源大小:2911k
文件大小:36k
源码类别:

uCOS

开发平台:

C/C++

  1. /****************************************Copyright (c)**************************************************
  2. **                               Hangzhou yh software  Co.,LTD.
  3. **                                     
  4. **                                 http://www.armgcc.com
  5. **
  6. **--------------File Info-------------------------------------------------------------------------------
  7. ** File name: sdcmd.c
  8. ** Last modified Date: 2007-10-15
  9. ** Last Version: V1.0
  10. ** Descriptions: SD/MMC 读写模块: 物理层 ---- SD/MMC卡SPI模式支持的命令 
  11. **------------------------------------------------------------------------------------------------------
  12. ** Created by: lhlzjut@hotmail.com
  13. ** Created date: 2007-10-15
  14. ** Version: V1.0
  15. ** Descriptions: The original version
  16. **
  17. **------------------------------------------------------------------------------------------------------
  18. ********************************************************************************************************/
  19. #include <stdio.h>
  20. #include "sdhal.h"
  21. #include "sdcrc.h"
  22. #include "sdcmd.h"
  23. #include "sddriver.h"
  24. #if SD_UCOSII_EN    
  25. #include  "ucos_ii.h"
  26. #endif
  27. /********************************************************************************************************************
  28. ** 函数名称: INT8U SD_SendCmd() Name:   INT8U SD_SendCmd()
  29. ** 功能描述: 向卡发送命令,并取得响应 Function: send command to the card,and get a response
  30. ** 输   入: INT8U cmd     : 命令字 Input:   INT8U cmd     : command byte
  31.  INT8U *param : 命令参数,长度为4字节   INT8U *param : command parameter,length is 4 bytes  
  32.  INT8U resptype : 响应类型   INT8U resptype: response type
  33.  INT8U *resp : 响应,长度为1-5字节   INT8U *resp : response,length is 1-5 bytes
  34. ** 输   出: 0:   正确    >0:   错误码    Output:   0:  right >0:  error code
  35. ********************************************************************************************************************/
  36. INT8U SD_SendCmd(INT8U cmd, INT8U *param, INT8U resptype, INT8U *resp)
  37. {
  38. INT32 i,rlen;
  39. INT8U tmp;
  40.     
  41. SPI_CS_Assert();
  42.    
  43.     SPI_SendByte((cmd & 0x3F) | 0x40);  /* 发送命令头和命令字 send command header and word */
  44.     
  45.     for (i = 3; i >= 0; i--)
  46.         SPI_SendByte(param[i]);  /* 发送参数 send parameters */
  47. #if SD_CRC_EN
  48. tmp = SD_GetCmdByte6((cmd & 0x3F) | 0x40, param);
  49. SPI_SendByte(tmp);
  50. #else
  51.     SPI_SendByte(0x95);    /* CRC校验码,只用于第1个命令 CRC,only used for the first command */
  52. #endif 
  53.     
  54.     rlen = 0;
  55.     switch (resptype)  /* 根据不同的命令,得到不同的响应长度 */
  56.     {  /* according various command,get the various response length */
  57.    case R1:  rlen = 1;  break;
  58.       case R1B: rlen = 1;  break;
  59.          
  60.      case R2:  rlen = 2;  break;
  61.          
  62.     case R3:  rlen = 5;  break;
  63.          
  64.      default:  
  65.  SPI_SendByte(0xFF);
  66.         SPI_CS_Deassert();  
  67.           return SD_ERR_CMD_RESPTYPE;  /* 返回命令响应类型错误 return error of command response type */
  68.     }
  69.     i = 0;
  70.     do   /* 等待响应,响应的开始位为0 */
  71.     {  /* Wait for a response,a response is a start bit(zero) */ 
  72.         tmp = SPI_RecByte();
  73.         i++;
  74.     }while (((tmp & 0x80) != 0) && (i < SD_CMD_TIMEOUT));
  75.     
  76.     if (i >= SD_CMD_TIMEOUT)
  77.     {  
  78.         SPI_CS_Deassert();
  79.         return SD_ERR_CMD_TIMEOUT;  /* 返回命令超时 return response timeout of command */
  80.     }
  81.     
  82.     for (i = rlen - 1; i >= 0; i--)
  83.     {
  84.         resp[i] = tmp;
  85.         tmp = SPI_RecByte();    /* 循环的最后发送8clock  at the last recycle,clock out 8 clock */
  86.     }
  87.       
  88.     SPI_CS_Deassert();
  89.     return SD_NO_ERR;  /* 返回执行成功 return perform sucessfully */
  90. }
  91. /********************************************************************************************************************
  92. ** 函数名称: void SD_PackParam() Name:   void SD_PackParam()
  93. ** 功能描述: 将32位的参数转为字节形式 Function: change 32bit parameter to bytes form 
  94. ** 输   入: INT8U *parameter: 字节参数缓冲区 Input:   INT8U *parameter: the buffer of bytes parameter
  95.  INT32U value    : 32位参数   INT32U value    : 32bit parameter
  96. ** 输   出: 无 Output:   NULL
  97. *********************************************************************************************************************/
  98. void SD_PackParam(INT8U *parameter, INT32U value)
  99. {
  100.     parameter[3] = (INT8U)(value >> 24);
  101.     parameter[2] = (INT8U)(value >> 16);
  102.     parameter[1] = (INT8U)(value >> 8);
  103.     parameter[0] = (INT8U)(value);
  104. }
  105. /********************************************************************************************************************
  106. ** 函数名称: INT8U SD_BlockCommand() Name:   INT8U SD_BlockCommand()
  107. ** 功能描述: 块命令 Function: command about block operation
  108. ** 输   入: INT8U cmd      : 命令字 Input:   INT8U cmd       : command byte 
  109.  INT8U resptype  : 响应类型   INT8U resptype  : response type
  110.  INT32U parameter: 块操作参数     INT32U parameter: parameter of block operation
  111. ** 输   出: 0:   正确    >0:   错误码    Output:   0:  right >0:  error code
  112. *********************************************************************************************************************/
  113. INT8U SD_BlockCommand(INT8U cmd, INT8U resptype, INT32U parameter)
  114. {
  115. INT8U param[4],resp,ret;
  116. parameter <<= SD_BLOCKSIZE_NBITS;  /* 调整地址:左移9位 adjust address: move 9 bits left */
  117. SD_PackParam(param, parameter);  /* 将参数转化为字节形式 change the parameter to bytes form */
  118. ret = SD_SendCmd(cmd, param, resptype, &resp);
  119. if (ret != SD_NO_ERR)
  120.      return ret;    /* 结束数据传输失败 stop transmission operation fail */
  121. if (resp != 0) {
  122.  return SD_ERR_CMD_RESP;    /* 响应错误 response is error */
  123. }
  124.  
  125. return SD_NO_ERR;
  126. }
  127. /*
  128. ************************************************
  129.   下面为SD卡SPI命令
  130. ************************************************
  131. */
  132. /********************************************************************************************************************
  133. ** 函数名称: INT8U SD_ResetSD() Name:   INT8U SD_ResetSD()
  134. ** 功能描述: 复位SD/MMC卡 Function: reset SD/MMC card
  135. ** 输   入: 无 Input:   NULL
  136. ** 输   出: 0:   正确    >0:   错误码    Output:   0:  right >0:  error code
  137. *********************************************************************************************************************/
  138. INT8U SD_ResetSD(void)
  139. {
  140. INT8U param[4] = {0,0,0,0},resp;
  141.     return (SD_SendCmd(CMD0, param, CMD0_R, &resp)); /* 复位命令 command that reset card */
  142. }
  143. /********************************************************************************************************************
  144. ** 函数名称: INT8U SD_ReadCSD() Name:   INT8U SD_ReadCSD()
  145. ** 功能描述: 读SD/MMC卡的CSD寄存器 Function: read CSD register of SD/MMC card 
  146. ** 输   入: INT8U csdlen  : 寄存器长度(固定为16)   INT8U csdlen  : len of register (fixed,is 16)
  147.  INT8U *recbuf : 接收缓冲区       INT8U *recbuf : recbuffer
  148. ** 输   出: 0:   正确    >0:   错误码    Output:   0:  right >0:  error code
  149. *********************************************************************************************************************/
  150. INT8U SD_ReadCSD(INT8U csdlen, INT8U *recbuf)
  151. {
  152.     INT8U param[4] = {0,0,0,0},resp,ret;
  153.   
  154.     ret = SD_SendCmd(CMD9, param, CMD9_R, &resp); /* 读CSD寄存器命令 command that read CSD register */
  155.     if (ret != SD_NO_ERR) 
  156.         return ret;
  157.   
  158.     if (resp != 0)
  159.         return SD_ERR_CMD_RESP; /* 响应错误 response is error */
  160.      
  161. return (SD_ReadRegister(csdlen, recbuf));
  162. }
  163. /*******************************************************************************************************************
  164. ** 函数名称: INT8U SD_ReadCID() Name:   INT8U SD_ReadCID()
  165. ** 功能描述: 读SD卡的CID寄存器 Function: read CID register of sd card
  166. ** 输   入: INT8U cidlen  : 寄存器长度(固定为16)   INT8U cidlen  : len of register (fixed,is 16)
  167.  INT8U *recbuf : 接收缓冲区       INT8U *recbuf : recbuffer
  168. ** 输   出: 0:   正确    >0:   错误码    Output:   0:  right >0:  error code
  169. ********************************************************************************************************************/
  170. #if SD_ReadCID_EN
  171. INT8U SD_ReadCID(INT8U cidlen, INT8U *recbuf)
  172. {
  173.     INT8U param[4] = {0,0,0,0},resp,ret;
  174.  
  175.     ret = SD_SendCmd(CMD10, param, CMD10_R, &resp); /* 读CID寄存器命令 command that read CID register */
  176.     if ( ret != SD_NO_ERR)
  177.     return ret;   
  178.    
  179.     if (resp != 0)
  180.         return SD_ERR_CMD_RESP; /* 响应错误 response is error */
  181.       
  182.    return (SD_ReadRegister(cidlen, recbuf));
  183. }
  184. #endif
  185. /********************************************************************************************************************
  186. ** 函数名称: INT8U SD_StopTransmission() Name:   INT8U SD_StopTransmission()
  187. ** 功能描述: 停止数据传输 Function: stop data transmission 
  188. ** 输   入: 无   Input:    NULL
  189. ** 输   出: 0:   正确    >0:   错误码    Output:   0:  right >0:  error code
  190. *********************************************************************************************************************/
  191. INT8U SD_StopTransmission(void)
  192. {
  193. INT8U param[4] = {0,0,0,0},resp;
  194.   return (SD_SendCmd(CMD12, param, CMD12_R, &resp)); /* 结束数据传输命令失败 stop transmission command fail */
  195. }
  196. /*********************************************************************************************************************
  197. ** 函数名称: INT8U SD_ReadCard_Status() Name:   INT8U SD_ReadCard_Status()
  198. ** 功能描述: 读SD/MMC卡的 Card Status 寄存器 Function: read Card Status register of SD/MMC card 
  199. ** 输   入: INT8U len:   寄存器长度(固定为2)   INT8U len:      len of register (fixed,is 2)
  200.  INT8U *recbuf : 接收缓冲区       INT8U *recbuf : recbuffer
  201. ** 输   出: 0:   正确    >0:   错误码    Output:   0:  right >0:  error code
  202. **********************************************************************************************************************/
  203. INT8U SD_ReadCard_Status(INT8U len, INT8U *buffer)
  204. {
  205.     INT8U param[4] = {0,0,0,0};
  206.     return (SD_SendCmd(CMD13, param, CMD13_R, buffer)); /* 读 Card Status 寄存器 */
  207.          /* read register of Card Status */
  208. }
  209. /********************************************************************************************************************
  210. ** 函数名称: INT8U SD_SetBlockLen() Name:   INT8U SD_SetBlockLen()
  211. ** 功能描述: 设置一个块的长度 Function: set a block len of card 
  212. ** 输   入: INT32U length : 块的长度值 Input:   INT32U length : the length of a block
  213. ** 输   出: 0:   正确    >0:   错误码    Output:   0:  right >0:  error code
  214. *********************************************************************************************************************/
  215. INT8U SD_SetBlockLen(INT32U length)
  216. {
  217. INT8U param[4],resp,ret;
  218.   
  219.     SD_PackParam(param, length); /* 将参数转化为字节形式 change the parameter to bytes form */
  220.           
  221.     ret = SD_SendCmd(CMD16, param, CMD16_R, &resp);
  222.     if (ret != SD_NO_ERR)
  223.   return ret; /* 设置块的长度为length失败 set the length of block to length fail */
  224. if (resp != 0)
  225.      return SD_ERR_CMD_RESP;     /* 响应错误 response is error */
  226.     
  227.     return SD_NO_ERR;  /* 返回执行成功 return perform sucessfully */
  228. }
  229. /********************************************************************************************************************
  230. ** 函数名称: INT8U SD_ReadSingleBlock() Name:   INT8U SD_ReadSingleBlock()
  231. ** 功能描述: 读单块命令 Function: read single block command
  232. ** 输   入: INT32U blockaddr: 块地址 Input:   INT32U blockaddr: block address
  233. ** 输   出: 0:   正确    >0:   错误码    Output:   0:  right >0:  error code
  234. *********************************************************************************************************************/
  235. INT8U SD_ReadSingleBlock(INT32U blockaddr)
  236. {
  237. return (SD_BlockCommand(CMD17, CMD17_R, blockaddr)); /* 读单块命令 command that read single block */
  238. }
  239. /********************************************************************************************************************
  240. ** 函数名称: INT8U SD_ReadMultipleBlock() Name:   INT8U SD_ReadMultipleBlock()
  241. ** 功能描述: 读多块命令 Function: read multiple block command 
  242. ** 输   入: INT32U blockaddr: 块地址 Input:   INT32U blockaddr: block address
  243. ** 输   出: 0:   正确    >0:   错误码    Output:   0:  right >0:  error code
  244. *********************************************************************************************************************/
  245. INT8U SD_ReadMultipleBlock(INT32U blockaddr)
  246. {
  247. return (SD_BlockCommand(CMD18, CMD18_R, blockaddr)); /* 读多块命令 command that read multiple block */
  248. }
  249. /********************************************************************************************************************
  250. ** 函数名称: INT8U SD_WriteSingleBlock() Name:   INT8U SD_WriteSingleBlock()
  251. ** 功能描述: 写单块命令 Function: write single block command
  252. ** 输   入: INT32U blockaddr: block address Input:   INT32U blockaddr: block address
  253. ** 输   出: 0:   正确    >0:   错误码    Output:   0:  right >0:  error code
  254. *********************************************************************************************************************/
  255. INT8U SD_WriteSingleBlock(INT32U blockaddr)
  256. {
  257. return (SD_BlockCommand(CMD24, CMD24_R, blockaddr)); /* 写单块命令 command that write single block */
  258. }
  259. /********************************************************************************************************************
  260. ** 函数名称: INT8U SD_WriteMultipleBlock() Name:   INT8U SD_WriteMultipleBlock()
  261. ** 功能描述: 写多块命令 Function: write multiple block command
  262. ** 输   入: INT32U blockaddr: 块地址 Input:   INT32U blockaddr: block address
  263. ** 输   出: 0:   正确    >0:   错误码    Output:   0:  right >0:  error code
  264. *********************************************************************************************************************/
  265. INT8U SD_WriteMultipleBlock(INT32U blockaddr)
  266. {
  267. return (SD_BlockCommand(CMD25, CMD25_R, blockaddr)); /* 写多块命令 command that write multiple block */
  268. }
  269. /********************************************************************************************************************
  270. ** 函数名称: INT8U SD_ProgramCSD() Name:   INT8U SD_ProgramCSD()
  271. ** 功能描述: 写CSD寄存器 Function: write CSD register
  272. ** 输   入: INT8U *buff     : CSD寄存器内容 Input:   INT8U *buff      : the content of CSD register
  273.  INT8U len     : CSD寄存器长度      INT8U len   : the length of CSD register
  274. ** 输   出: 0:   正确    >0:   错误码    Output:   0:  right >0:  error code
  275. ********************************************************************************************************************/
  276. #if SD_ProgramCSD_EN
  277. INT8U SD_ProgramCSD(INT8U len, INT8U *buff)
  278. {
  279. INT8U param[4] = {0,0,0,0},resp,ret;
  280. if (len != 16) return SD_ERR_USER_PARAM;
  281. ret = SD_SendCmd(CMD27, param, CMD27_R, &resp);  /* 发送写CSD寄存器命令 send command that write CSD */
  282. if (ret != SD_NO_ERR)
  283. return ret;
  284.         
  285.     if (resp != 0)    
  286.         return SD_ERR_CMD_RESP;
  287. buff[15] = (SD_GetCRC7(buff, 15) << 1) + 0x01;   /* 计算CSD中的crc 位域 calculate crc field in CSD */
  288. return(SD_WriteBlockData(0, 16, buff));
  289. }
  290. /********************************************************************************************************************
  291. ** 函数名称: INT8U SD_GetCRC7() Name:   INT8U SD_GetCRC7()
  292. ** 功能描述: 计算CRC7 Function: calculate crc7
  293. ** 输   入: INT8U *pSource: 数据 Input:    INT8U *pSource: data
  294.  INT16U len    : 数据长度   INT16U len   : data length
  295. ** 输   出: CRC7码 Output:   CRC7 code
  296. *********************************************************************************************************************/
  297. INT8U SD_GetCRC7(INT8U *pSource, INT16U len)
  298. {
  299. INT8U i = 0, j;
  300. INT8U reg = 0;
  301. do
  302. {
  303.     for (j = 0; j < 8; j++)
  304.     {
  305. reg <<= 1;
  306. reg ^= ((((pSource[i] << j) ^ reg) & 0x80) ? 0x9 : 0);
  307.     }
  308.     
  309.     i++;
  310.     
  311. }while(i < len);
  312. return reg;
  313. }
  314. #endif
  315. #if SD_EraseBlock_EN
  316. /********************************************************************************************************************
  317. ** 函数名称: INT8U SD_EraseStartBlock() Name:   INT8U SD_EraseStartBlock()
  318. ** 功能描述: 设置块擦除起始地址 Function: select the start block address of erasing operation 
  319. ** 输   入: INT32U startblock: 块地址 Input:    INT32U startblock : block address
  320. ** 输   出: 0:   正确    >0:   错误码    Output:   0:  right    >0:  error code
  321. *********************************************************************************************************************/
  322. INT8U SD_EraseStartBlock(INT32U startblock)
  323. {
  324. if (sds.card_type == CARDTYPE_SD)
  325. return (SD_BlockCommand(CMD32, CMD32_R, startblock)); /* 发送擦除起始块地址 send the start block address of erasing operation */
  326. else
  327. return (SD_BlockCommand(CMD35, CMD35_R, startblock)); /* 发送擦除起始块地址 send the start block address of erasing operation */
  328. }
  329. /********************************************************************************************************************
  330. ** 函数名称: INT8U SD_EraseEndBlock() Name:   INT8U SD_EraseEndBlock()
  331. ** 功能描述: 设置块擦除终止地址 Function: select the end block address of erasing operation  
  332. ** 输   入: INT32U endblock: 块地址 Input:   INT32U Length : block address
  333. ** 输   出: 0:   正确    >0:   错误码    Output:   0:  right    >0:  error code
  334. *********************************************************************************************************************/
  335. INT8U SD_EraseEndBlock(INT32U endblock)
  336. {
  337. if (sds.card_type == CARDTYPE_SD)
  338. return (SD_BlockCommand(CMD33, CMD33_R, endblock));     /* 发送擦除终止块地址 send the end block address of erasing operation */
  339. else
  340. return (SD_BlockCommand(CMD36, CMD36_R, endblock));     /* 发送擦除终止块地址 send the end block address of erasing operation */
  341. }
  342. /********************************************************************************************************************
  343. ** 函数名称: INT8U SD_EraseSelectedBlock() Name:   INT8U SD_EraseSelectedBlock()
  344. ** 功能描述: 擦除已选中的块 Function: erase block selected
  345. ** 输   入: 无 Input:   NULL
  346. ** 输   出: 0:   正确    >0:   错误码    Output:   0:  right >0:  error code
  347. *********************************************************************************************************************/
  348. INT8U SD_EraseSelectedBlock(void)
  349. {
  350. INT8U param[4],resp,tmp;
  351. SD_PackParam(param, 0);
  352. tmp = SD_SendCmd(CMD38, param, CMD38_R, &resp);       /* 擦除所选择的块  erase blocks selected */
  353. if (tmp != SD_NO_ERR)
  354. return tmp;  
  355. if (SD_WaitBusy(SD_WAIT_ERASE) != SD_NO_ERR) /* 等待擦除完成 wait for finishing erasing */
  356. return SD_ERR_TIMEOUT_ERASE;
  357. else
  358. return SD_NO_ERR;
  359. }
  360. #endif
  361. /*********************************************************************************************************************
  362. ** 函数名称: INT8U SD_ReadOCR() Name:   INT8U SD_ReadOCR()
  363. ** 功能描述: 读操作条件寄存器OCR Function: read OCR register of card
  364. ** 输   入: INT8U ocrlen  : 寄存器长度(固定为4) Input:   INT8U ocrlen  : len of register (fixed,is 4)
  365.  INT8U *recbuf : 接收缓冲区       INT8U *recbuf : recbuffer
  366. ** 输   出: 0:   正确    >0:   错误码    Output:   0:  right >0:  error code
  367. **********************************************************************************************************************/
  368. INT8U SD_ReadOCR(INT8U ocrlen, INT8U *recbuf)
  369. {
  370.     INT8U param[4] = {0,0,0,0},resp[5],tmp;
  371.     tmp = SD_SendCmd(CMD58, param, CMD58_R, resp); /* 读 OCR 寄存器命令 */
  372.     if (tmp != SD_NO_ERR) /* read OCR register command */
  373.      return tmp;  
  374.     
  375.     if (resp[0] != 0)
  376.         return SD_ERR_CMD_RESP;   /* 响应错误 response is error */
  377.     
  378.     for (tmp = 0; tmp < 4; tmp++)
  379.      recbuf[tmp] = resp[tmp + 1]; /* 复制OCR寄存器内容到接收缓冲区 */
  380.     
  381.     return SD_NO_ERR;
  382. }
  383. /********************************************************************************************************************
  384. ** 函数名称: INT8U SD_EnableCRC() Name:   INT8U SD_EnableCRC()
  385. ** 功能描述: 使能SD卡的CRC校验功能 Function: enable crc check of SD Card 
  386. ** 输   入: INT8U bEnable : 1:使能 0:禁止 Input:   INT8U bEnable : 1:enable  0: disable
  387. ** 输   出: 0:   正确    >0:   错误码    Output:   0:  right >0:  error code
  388. *********************************************************************************************************************/
  389. #if SD_CRC_EN
  390. INT8U SD_EnableCRC(INT8U bEnable)
  391. {
  392. INT8U param[4],resp,ret;
  393. if (bEnable == 1)
  394. param[0] = 1; /* 使能crc enable crc */
  395. else
  396. param[1] = 0;  /* 禁止crc disalbe crc */
  397. ret = SD_SendCmd(CMD59, param, CMD59_R, &resp); /* "使能/禁止CRC"命令 enable/disable crc command */
  398. if (ret != SD_NO_ERR)
  399.         return ret;  
  400.     
  401.     if (resp != 0)    
  402.         return SD_ERR_CMD_RESP; /* 响应错误 response is error */
  403.  
  404. return SD_NO_ERR;
  405. }
  406. #endif
  407. /*********************************************************************************************************************
  408. ** 函数名称: INT8U SD_ReadSD_Status()      Name:    INT8U SD_ReadSD_Status()
  409. ** 功能描述: 读SD卡的 SD_Status 寄存器      Function: read SD_Status register of sd card 
  410. ** 输   入: INT8U sdslen   : 寄存器长度(固定为64)  Input:    INT8U sdslen: len of register (fixed,is 64)
  411.  INT8U *recbuf  : 接收缓冲区        INT8U *recbuf: recbuffer
  412. ** 输   出: 0:   正确    >0:   错误码     Output:   0:  right >0:  error code
  413. ** 注    意: 只有SD卡才有SD Status 寄存器  Note:     only SD card have SD Status Register
  414. **********************************************************************************************************************/
  415. #if SD_ReadSD_Status_EN
  416. INT8U SD_ReadSD_Status(INT8U sdslen, INT8U *recbuf)
  417. {
  418.     INT8U param[4] = {0,0,0,0},resp[2],ret;
  419.     
  420.     ret = SD_SendCmd(CMD55, param, CMD55_R, resp); /* 后续命令为一个应用命令 */
  421.     if (ret != SD_NO_ERR)
  422.      return ret; /* command that the followed commnad is a specific application */
  423.       
  424.     if (resp[0] != 0)
  425.         return SD_ERR_CMD_RESP; /* 响应错误 response is error */
  426.     
  427.     ret = SD_SendCmd(ACMD13, param, ACMD13_R, resp); /* 读 SD_Status 命令 */
  428.     if (ret != SD_NO_ERR)
  429.      return ret; /* command that read SD_Status register */
  430.    
  431.     if ((resp[0] != 0) || (resp[1] != 0))
  432.         return SD_ERR_CMD_RESP; /* 响应错误 response is error */
  433.         
  434. return (SD_ReadBlockData(sdslen, recbuf)); /* 读出寄存器内容 read the content of the register */
  435. }
  436. #endif
  437. /*******************************************************************************************************************
  438. ** 函数名称: INT8U SD_ReadSCR() Name:   INT8U SD_ReadSCR()
  439. ** 功能描述: 读SD卡的 SCR 寄存器 Function: read SCR register of SD card 
  440. ** 输   入: INT8U scrlen   : 寄存器长度(固定为8)  Input:    INT8U scrlen  : len of register (fixed,is 8)
  441.  INT8U *recbuf  : 接收缓冲区   INT8U *recbuf  : recieve buffer
  442. ** 输   出: 0:   正确    >0:   错误码    Output:   0:  right >0:  error code
  443. ** 备  注: MMC卡没有该寄存器 Note:   MMC Card have not this register
  444. ********************************************************************************************************************/
  445. #if SD_ReadSCR_EN
  446. INT8U SD_ReadSCR(INT8U scrlen, INT8U *recbuf)
  447. {
  448.     INT8U param[4] = {0,0,0,0},resp,ret;
  449.     
  450.     ret = SD_SendCmd(CMD55, param, CMD55_R, &resp); /* 后续命令为一个应用命令 */
  451.     if (ret != SD_NO_ERR) /* command that the followed commnad is a specific application */
  452.      return ret;
  453.       
  454.     if (resp != 0)
  455.         return SD_ERR_CMD_RESP; /* 响应错误 response is error */
  456.     
  457.     ret = SD_SendCmd(ACMD51, param, ACMD51_R, &resp);   /* 发送读 SD Status 命令*/
  458.     if (ret != SD_NO_ERR) /* command that read SD Status register */
  459.     return ret;
  460.     
  461.     if (resp != 0)
  462.         return SD_ERR_CMD_RESP;   /* 响应错误 response is error */
  463.         
  464. return (SD_ReadBlockData(scrlen, recbuf));   /* 读出寄存器内容 read the content of the register */
  465. }
  466. #endif
  467. /********************************************************************************************************************
  468. ** 函数名称: INT8U SD_GetNumWRBlcoks() Name:   INT8U SD_GetNumWRBlcoks()
  469. ** 功能描述: 得到正确写入的块数 Function: get the block numbers that written correctly
  470. ** 输   入: INT32U *blocknum: 返回的块数 Input:   INT32U blocknum : the block numbers returned
  471. ** 输   出: 0:   正确    >0:   错误码    Output:   0:  right >0:  error code
  472. ** 注  意: MMC卡没有该命令 Note:     MMC Card have no this command
  473. *********************************************************************************************************************/
  474. #if SD_WriteMultiBlock_EN
  475. INT8U SD_GetNumWRBlcoks(INT32U *blocknum)
  476. {
  477.     INT8U tmp[4] = {0,0,0,0},resp,ret;
  478.   
  479.     ret = SD_SendCmd(CMD55, tmp, CMD55_R, &resp);     /* 后续命令为一个应用命令 */
  480.     if (ret != SD_NO_ERR)   /* command that the followed commnad is a specific application */
  481.      return ret;
  482.       
  483.     if (resp != 0)
  484.      return SD_ERR_CMD_RESP;    
  485.  
  486.     ret = SD_SendCmd(ACMD22, tmp, ACMD22_R, &resp);    /* 读取正确写入的块数命令 */
  487.     if (ret != SD_NO_ERR)  /* command that read the numbers of block written correctly */
  488.     return ret;     
  489.      
  490. if (resp != 0)
  491.      return SD_ERR_CMD_RESP;  /* 响应错误 response is error */
  492.     
  493.     ret = SD_ReadBlockData(4, tmp);  /* 读块数 read the numbvers of block */
  494.     if (ret != SD_NO_ERR)
  495.      return ret;
  496.     
  497.     *blocknum = (tmp[0] << 24) + (tmp[1] << 16) + (tmp[2] << 8) + tmp[3];
  498.       /* 转换为32位 change to 32 bits */
  499. return SD_NO_ERR;      /* 返回执行成功 return perform sucessfully */
  500. }
  501. #endif
  502. /*********************************************************
  503.      下面为一些数据传输函数
  504. **********************************************************/
  505. /********************************************************************************************************************
  506. ** 函数名称: INT8U SD_ReadRegister() Name:   INT8U SD_ReadRegister()
  507. ** 功能描述: 从SD卡读取数据 Function: read data from SD card
  508. ** 输   入: INT32U len   : 长度 Input:   INT32U len   : length
  509.  INT8U *recbuf: 接收缓冲区     INT8U *recbuf: receive buffer
  510. ** 输   出: 0:   正确    >0:   错误码    Output:   0:  right >0:  error code
  511. *********************************************************************************************************************/
  512. INT8U SD_ReadRegister(INT32U len, INT8U *recbuf)
  513. {
  514. INT32U i = 0;
  515. INT8U resp;
  516.     SPI_CS_Assert();
  517.     do{     /* 等待数据起始令牌 wait for data start token */
  518.         resp = SPI_RecByte();
  519.      i++;
  520.     }while((resp == 0xFF) && (i < SD_READREG_TIMEOUT));    
  521.     
  522.     if (i >= SD_READREG_TIMEOUT)
  523.     {
  524.      SPI_CS_Deassert();
  525.      return SD_ERR_TIMEOUT_READ; /* 超时, 返回错误 timeout, return error */
  526.    }
  527.   
  528.     if (resp != SD_TOK_READ_STARTBLOCK)
  529.     { /* 不是收到数据起始令牌 not receive data start token */
  530. recbuf[0] = resp;
  531. i = 1; /* 还有len - 1个字节要接收 still len - 1 bytes will be received */
  532.     }
  533.     else
  534.     i = 0; /* 收到数据起始令牌,还有len个字节要接收 received data start token,still len bytes will be received */
  535.       
  536.     for (; i < len; i++)
  537.     recbuf[i] = SPI_RecByte(); /* 接收数据 receive data */
  538.    
  539.     i = SPI_RecByte();
  540.     i = (i << 8) + SPI_RecByte();     /* 读取16位CRC get 16-bit CRC */
  541. #if SD_CRC_EN 
  542.     if (i != SD_GetCRC16(recbuf, len))
  543.     { /* CRC校验错误 CRC check is error */
  544.     SPI_SendByte(0xFF);
  545.     SPI_CS_Deassert();
  546.    return SD_ERR_DATA_CRC16; /* 返回RCR16错误  return error of CRC16 */
  547.    }    
  548. #endif   
  549.   
  550.     SPI_SendByte(0xFF); /* 返回之前发送8个clock  clock out 8 clk before return */
  551.     SPI_CS_Deassert();
  552.     
  553. return SD_NO_ERR;
  554. }
  555. /*******************************************************************************************************************
  556. ** 函数名称: INT8U SD_ReadBlockData() Name:   INT8U SD_ReadBlockData()
  557. ** 功能描述: 从卡中读取数据块 Function: read block data from card
  558. ** 输   入: INT32U len    : 长度 Input:   INT32U len    : length
  559.  INT8U *recbuf : 接收缓冲区   INT8U *recbuf : the buffer of receive
  560. ** 输   出: 0:   正确    >0:   错误码    Output:   0:  right >0:  error code
  561. *******************************************************************************************************************/
  562. INT8U SD_ReadBlockData(INT32U len, INT8U *recbuf)
  563. {
  564.     INT8U tmp;
  565.     INT32U i = 0,timeout;
  566. #if SD_UCOSII_EN    
  567.     timeout = SD_UCOSII_SMALLWAIT; /* 很少的等待时间 small wait time */
  568. #else
  569. timeout = sds.timeout_read; /* 等待接收数据开始令牌最长时间 wait time that receive data start token */
  570. #endif  
  571.     
  572.     SPI_CS_Assert();    
  573.     do
  574.     {       /* 等待接收数据开始令牌0xFE  wait for receiving data start token 0xFE */
  575.         tmp = SPI_RecByte();
  576.         i++;
  577.     }while((tmp == 0xFF) && (i < timeout));
  578. #if SD_UCOSII_EN    
  579.     if (i >= timeout)
  580.     { /* 继续等待(挂起任务) continue to wait(suspend task) */
  581.     timeout = sds.timeout_read;
  582.     i = 0;
  583.     do
  584.      {
  585.          OSTimeDly(1); /* 挂起该任务1 tick(suspend task 1 tick) */
  586.          tmp = SPI_RecByte();
  587.           i++;
  588.     }while((tmp == 0xFF) && (i < timeout));
  589. }
  590. #endif
  591. if (i >= timeout)
  592. {
  593. SPI_CS_Deassert();
  594.         return SD_ERR_TIMEOUT_READ; /* 返回读超时错误码  return error timeout error code of reading */
  595. }
  596. if (tmp != SD_TOK_READ_STARTBLOCK) /* 块读开始令牌错误 read start block token is error */
  597. {
  598. SPI_SendByte(0xFF);
  599. SPI_CS_Deassert();
  600. return SD_ERR_DATA_START_TOK;
  601. }
  602. for (i = 0; i < len; i++) {
  603.     recbuf[i] = SPI_RecByte(); /* 接收数据 receive data */
  604. }
  605.    
  606.     i = SPI_RecByte();
  607.     i = (i << 8) + SPI_RecByte();     /* 读取16位CRC get 16-bit CRC */
  608. #if SD_CRC_EN 
  609.     if (i != SD_GetCRC16(recbuf, len))
  610.     {
  611.     SPI_SendByte(0xFF);  /* CRC校验错误 CRC check is error */
  612.     SPI_CS_Deassert();
  613.    return SD_ERR_DATA_CRC16; /* 返回RCR16错误  return error of CRC16 */
  614.    }    
  615. #endif   
  616. SPI_SendByte(0xFF); 
  617. SPI_CS_Deassert();
  618.    return SD_NO_ERR; /* 返回函数执行成功 return function perform sucessfully */
  619. }
  620. /*******************************************************************************************************************
  621. ** 函数名称: INT8U SD_WriteBlockData() Name:   INT8U SD_WriteBlockData()
  622. ** 功能描述: 向卡写数据块 Function: write block data to card
  623. ** 输   入: INT8U bmulti  : 是否为多块操作1:是0:否 Input:   INT8U bmulti   : multi blocks operate 1:Y 0:N 
  624.  INT32U len    : 长度      INT32U len     : length
  625.  INT8U *sendbuf: 发送缓冲区     INT8U *sendbuf : the buffer of send
  626. ** 输   出: 0:   正确    >0:   错误码    Output:   0:  right >0:  error code
  627. ********************************************************************************************************************/
  628. INT8U SD_WriteBlockData(INT8U bmulti, INT32U len, INT8U *sendbuf)
  629. {
  630. INT16U i;
  631. #if 0
  632. INT16U tmp;
  633.     #endif  
  634. SPI_CS_Assert();
  635.     SPI_SendByte(0xFF); /* 开始发送数据之前发送8个clock clock out 8 clk before start */
  636.     
  637.     if (bmulti == 1)
  638.         SPI_SendByte(SD_TOK_WRITE_STARTBLOCK_M); /* 写多块开始令牌 start token of write multi blocks */
  639. else
  640. SPI_SendByte(SD_TOK_WRITE_STARTBLOCK); /* 写单块开始令牌 start token of write single block */
  641. for (i = 0; i < len; i++)
  642.         SPI_SendByte(sendbuf[i]); /* 发送数据 send data */
  643. #if SD_CRC_EN
  644. i = SD_GetCRC16(sendbuf,len); /* 计算CRC16 calculate CRC16 */
  645. #endif
  646. SPI_SendByte((i >> 8) & 0xFF);
  647. SPI_SendByte(i & 0xFF);  /* 发送CRC16校验码 send CRC16 check code */
  648.     
  649. #if 0
  650. tmp = SPI_RecByte();
  651.    if ((tmp & SD_RESP_DATA_MSK) != SD_RESP_DATA_ACCETPTED)
  652.    {
  653.     SPI_SendByte(0xFF); /* 返回之前发送8个clock  clock out 8 clk before return */
  654.     SPI_CS_Deassert();
  655.     return SD_ERR_DATA_RESP; /* 数据响应错误 data response error */
  656.     }
  657.     #endif   
  658.     SPI_CS_Deassert();
  659.      
  660.     if (SD_WaitBusy(SD_WAIT_WRITE) != SD_NO_ERR)
  661.      return SD_ERR_TIMEOUT_WRITE; /* 写入超时 write time out */
  662.     else
  663.      return SD_NO_ERR;  /* 写入正确 write right */
  664.  }
  665. /*******************************************************************************************************************
  666. ** 函数名称: void SD_StopMultiToken() Name:   void SD_StopMultiToken(void)
  667. ** 功能描述: 发送多块写停止令牌 Function: send the token that stop multiple block write
  668. ** 输   入: 无     Input:   NULL
  669. ** 输   出: 无 Output:   NULL
  670. ********************************************************************************************************************/
  671. void SD_StopMultiToken(void)
  672. {
  673. SPI_CS_Assert();
  674. SPI_SendByte(0xFF); /* 先发送8个clock send 8 clock first */
  675. SPI_SendByte(SD_TOK_STOP_MULTI); /* 发送停止数据传输令牌 send stop transmission token */
  676. SPI_RecByte();
  677.     SPI_CS_Deassert();
  678. }
  679. /********************************************************************************************************************
  680. ** 函数名称: void SD_WaitBusy() Name:   void SD_WaitBusy()
  681. ** 功能描述: 查询SD卡是否处于忙状态 Function: poll SD Card wheather it is busy
  682. ** 输   入: INT32U waittype: 超时类型 Input:   INT32U timeout: time out type
  683. ** 输   出: 0: 未超时  >0: 错误码 Output:   0: not time out   > 0: error code
  684. *********************************************************************************************************************/
  685. INT8U SD_WaitBusy(INT8U waittype)
  686. {
  687.     INT32U timeout, i = 0;
  688.     INT8U tmp;
  689.     
  690.    if (waittype == SD_WAIT_WRITE)
  691.    timeout = sds.timeout_write; /* 等待类型为写操作 wait type is write operation */
  692.    else
  693.    timeout = sds.timeout_erase;    /* 等待类型为擦除操作 wait type is erase operation */
  694.     
  695. #if SD_UCOSII_EN
  696.         timeout = SD_UCOSII_SMALLWAIT; /* 很少的等待时间 small wait time */
  697. #endif
  698.    
  699. SPI_CS_Assert();
  700.     do
  701.     {  /* 等待忙结束 wait for being busy end */
  702.         tmp = SPI_RecByte();
  703.         i++;
  704.     }while ((tmp != 0xFF) && (i < timeout)); /* 忙时收到的值为0 always receive 0 when card is busy */    
  705. #if SD_UCOSII_EN
  706. if (i >= timeout)
  707. { /* 很少等待后卡仍忙, after small wait, card is still busy */
  708.    if (waittype == SD_WAIT_WRITE)
  709.    timeout = sds.timeout_write;
  710.    else
  711.    timeout = sds.timeout_erase;   
  712. i = 0;
  713.     do
  714.     { 
  715.     OSTimeDly(1); /* 操作系统挂起1 tick  OS suspend 1 tick */
  716.         tmp = SPI_RecByte();
  717.         i++;
  718.      }while ((tmp != 0xFF) && (i < timeout)); /* 忙时收到的值为0 always receive 0 when card is busy */    
  719. }
  720. #endif
  721. if(i < timeout) 
  722. tmp = SD_NO_ERR; /* 返回0,表示没超时 return 0 indicate that operation is not time out */
  723. else 
  724. tmp = SD_ERR_TIMEOUT_WAIT; /* 返回错误码,表示超时 return error code indicate that operation is time out */
  725. SPI_SendByte(0xFF);
  726. SPI_CS_Deassert();
  727. return tmp; /* 返回执行结果 */
  728. }
  729. /********************************************************************************************************************
  730. ** 函数名称: void SD_SPIDelay() Name:   void SD_SPIDelay()
  731. ** 功能描述: SPI总线延时 Function: SPI Bus delay 
  732. ** 输   入: INT8U value: 延时值,不超过255     Input:   INT8U value : delay value,do not beyond 255
  733. ** 输   出: 无 Output:   NULL
  734. *********************************************************************************************************************/
  735. void SD_SPIDelay(INT8U value)
  736. {
  737.     INT8U i;
  738.     for (i = 0; i < value; i++)
  739.         SPI_SendByte(0xFF);   /* 发送0xFF clock out 0xFF */
  740. }