📄 sd_cmd.c
字号:
/*******************************************************************************
** 函数名称: INT8U SD_EnableCRC()
** 功能描述: 使能SD卡的CRC校验功能
** 输 入: INT8U bEnable : 1:使能 0:禁止
** 输 出: 0: 正确 >0: 错误码
*******************************************************************************/
#if SD_CRC_EN
INT8U SD_EnableCRC(INT8U bEnable)
{
INT8U param[4],resp,ret ;
if(bEnable==1)
param[0]=1 ;/* 使能crc enable crc */
else
param[1]=0 ;/* 禁止crc disalbe crc */
ret=SD_SendCmd(CMD59,param,CMD59_R,&resp);
/* "使能/禁止CRC"命令 enable/disable crc command */
if(ret!=SD_NO_ERR)
return ret ;
if(resp!=0)
return SD_ERR_CMD_RESP ;/* 响应错误 response is error */
return SD_NO_ERR ;
}
#endif
/*******************************************************************************
** 函数名称: INT8U SD_Read_SD_Status()
** 功能描述: 读SD卡的 SD_Status 寄存器
** 输 入: INT8U sdslen: 寄存器长度(固定为64)
INT8U *recbuf : 接收缓冲区
** 输 出: 0: 正确 >0: 错误码
*******************************************************************************/
#if SD_ReadSD_Status_EN
INT8U SD_ReadSD_Status(INT8U sdslen,INT8U *recbuf)
{
INT8U param[4]={0,0,0,0},resp[2],ret ;
ret=SD_SendCmd(CMD55,param,CMD55_R,resp);
/* 后续命令为一个应用命令 */
if(ret!=SD_NO_ERR)
return ret ;
/* command that the followed commnad is a specific application */
if(resp[0]!=0)
return SD_ERR_CMD_RESP ;
/* 响应错误 response is error */
ret=SD_SendCmd(ACMD13,param,ACMD13_R,resp);
/* 读 SD_Status 命令 */
if(ret!=SD_NO_ERR)
return ret ;
/* command that read SD_Status register */
if((resp[0]!=0)||(resp[1]!=0))
return SD_ERR_CMD_RESP ;/* 响应错误 response is error */
return(SD_ReadBlockData(sdslen,recbuf));
/* 读出寄存器内容 read the content of the register */
}
#endif
/*******************************************************************************
** 函数名称: INT8U SD_ReadSCR()
** 功能描述: 读SD卡的 SCR 寄存器
** 输 入: INT8U scrlen : 寄存器长度(固定为8)
INT8U *recbuf : 接收缓冲区
** 输 出: 0: 正确 >0: 错误码
*******************************************************************************/
#if SD_ReadSCR_EN
INT8U SD_ReadSCR(INT8U scrlen,INT8U *recbuf)
{
INT8U param[4]={0,0,0,0},resp,ret ;
ret=SD_SendCmd(CMD55,param,CMD55_R,&resp);
/* 后续命令为一个应用命令 */
/* command that the followed commnad is a specific application */
if(ret!=SD_NO_ERR)
return ret ;
if(resp!=0)
return SD_ERR_CMD_RESP ;
/* 响应错误 response is error */
ret=SD_SendCmd(ACMD51,param,ACMD51_R,&resp);
/* 发送读 SD_Status 命令*/
/* command that read SD_Status register */
if(ret!=SD_NO_ERR)
return ret ;
if(resp!=0)
return SD_ERR_CMD_RESP ;
/* 响应错误 response is error */
return(SD_ReadBlockData(scrlen,recbuf));
/* 读出寄存器内容 read the content of the register */
}
#endif
/*******************************************************************************
** 函数名称: INT8U SD_GetNumWRBlcoks()
** 功能描述: 得到正确写入的块数
** 输 入: INT32U *blocknum: 返回的块数
** 输 出: 0: 正确 >0: 错误码
*******************************************************************************/
#if SD_WriteMultiBlock_EN
INT8U SD_GetNumWRBlcoks(INT32U *blocknum)
{
INT8U tmp[4]={0,0,0,0},resp,ret ;
ret=SD_SendCmd(CMD55,tmp,CMD55_R,&resp);
/* 后续命令为一个应用命令 */
/* command that the followed commnad is a specific application */
if(ret!=SD_NO_ERR)
return ret ;
if(resp!=0)
return SD_ERR_CMD_RESP ;
ret=SD_SendCmd(ACMD22,tmp,ACMD22_R,&resp);
/* 读取正确写入的块数命令 */
/* command that read the numbers of block written correctly */
if(ret!=SD_NO_ERR)
return ret ;
if(resp!=0)
return SD_ERR_CMD_RESP ;
/* 响应错误 response is error */
ret=SD_ReadBlockData(4,tmp);
/* 读块数 read the numbvers of block */
if(ret!=SD_NO_ERR)
return ret ;
*blocknum=((INT32U)tmp[0]<<24)+((INT32U)tmp[1]<<16)+((INT32U)tmp[2]<<8)+tmp[3];
/* 转换为32位 change to 32 bits */
return SD_NO_ERR ;
/* 返回执行成功 return perform sucessfully */
}
#endif
/*********************************************************
下面为一些数据传输函数
/*******************************************************************************
** 函数名称: INT8U SD_ReadRegister()
** 功能描述: 从SD卡读取数据
** 输 入: INT32U len : 长度
INT8U *recbuf: 接收缓冲区
** 输 出: 0: 正确 >0: 错误码
*******************************************************************************/
INT8U SD_ReadRegister(INT32U len,INT8U *recbuf)
{
INT32U i=0 ;
INT8U resp ;
SPI_CS_Assert();
do
{
/* 等待数据起始令牌 wait for data start token */
resp=SPI_RecByte();
i++;
}
while((resp==0xFF)&&(i<SD_READREG_TIMEOUT));
if(i>=SD_READREG_TIMEOUT)
{
SPI_CS_Deassert();
return SD_ERR_TIMEOUT_READ ;
/* 超时, 返回错误 timeout, return error */
}
if(resp!=SD_TOK_READ_STARTBLOCK)
{
/* 不是收到数据起始令牌 not receive data start token */
recbuf[0]=resp ;
i=1 ;
/* 还有len - 1个字节要接收 still len - 1 bytes will be received */
}
else
i=0 ;
/* 收到数据起始令牌,还有len个字节要接收 received data start token,*/
for(;i<len;i++)
recbuf[i]=SPI_RecByte();
/* 接收数据 receive data */
i=SPI_RecByte();
i=(i<<8)+SPI_RecByte();
/* 读取16位CRC get 16-bit CRC */
#if SD_CRC_EN
if(i!=SD_GetCRC16(recbuf,len))
{
/* CRC校验错误 CRC check is error */
SPI_CS_Deassert();
SPI_SendByte(0xFF);
return SD_ERR_DATA_CRC16 ;
/* 返回RCR16错误 return error of CRC16 */
}
#endif
SPI_SendByte(0xFF);
/* 返回之前发送8个clock clock out 8 clk before return */
SPI_CS_Deassert();
return SD_NO_ERR ;
}
/*******************************************************************************
** 函数名称: INT8U SD_ReadBlockData()
** 功能描述: 从SD卡中读取数据块
** 输 入: INT32U len : 长度
INT8U *recbuf : 接收缓冲区
** 输 出: 0: 正确 >0: 错误码
*******************************************************************************/
INT8U SD_ReadBlockData(INT32U len,INT8U *recbuf)
{
INT8U tmp ;
INT32U i=0 ;
SPI_CS_Assert();
do
{
/* 等待接收数据开始令牌0xFE */
tmp=SPI_RecByte();
i++;
}
while((tmp==0xFF)&&(i<sds.timeout_read));
if(i>=sds.timeout_read)
{
SPI_CS_Deassert();
return SD_ERR_TIMEOUT_READ ;
/* 返回读超时错误码 return error timeout error code of reading */
}
/* 块读开始令牌错误 read start block token is error */
if(tmp!=SD_TOK_READ_STARTBLOCK)
{
SPI_SendByte(0xFF);
SPI_CS_Deassert();
return SD_ERR_DATA_START_TOK ;
}
for(i=0;i<len;i++)
recbuf[i]=SPI_RecByte();
/* 接收数据 receive data */
i=SPI_RecByte();
i=(i<<8)+SPI_RecByte();
/* 读取16位CRC get 16-bit CRC */
#if SD_CRC_EN
if(i!=SD_GetCRC16(recbuf,len))
{
/* CRC校验错误 CRC check is error */
SPI_SendByte(0xFF);
SPI_CS_Deassert();
return SD_ERR_DATA_CRC16 ;
/* 返回CRC16错误 return error of CRC16 */
}
#endif
SPI_SendByte(0xFF);
SPI_CS_Deassert();
return SD_NO_ERR ;
/* 返回函数执行成功 return function perform sucessfully */
}
/*******************************************************************************
** 函数名称: INT8U SD_WriteBlockData()
** 功能描述: 向sd卡写数据块
** 输 入: INT8U bmulti : 是否为多块操作1:是0:否 Input:
INT32U len : 长度
INT8U *sendbuf: 发送缓冲区
** 输 出: 0: 正确 >0: 错误码
*******************************************************************************/
INT8U SD_WriteBlockData(INT8U bmulti,INT32U len,INT8U*sendbuf)
{
INT16U i ;
INT8U tmp ;
SPI_CS_Assert();
SPI_SendByte(0xFF);
/* 开始发送数据之前发送8个clock clock out 8 clk before start */
if(bmulti==1)
SPI_SendByte(SD_TOK_WRITE_STARTBLOCK_M);
/* 写多块开始令牌 start token of write multi blocks */
else
SPI_SendByte(SD_TOK_WRITE_STARTBLOCK);
/* 写单块开始令牌 start token of write single block */
for(i=0;i<len;i++)
SPI_SendByte(sendbuf[i]);
/* 发送数据 send data */
#if SD_CRC_EN
i=SD_GetCRC16(sendbuf,len);
/* 计算CRC16 calculate CRC16 */
#endif
SPI_SendByte((i>>8)&0xFF);
SPI_SendByte(i&0xFF);
/* 发送CRC16校验码 send CRC16 check code */
tmp=SPI_RecByte();
if((tmp&SD_RESP_DATA_MSK)!=SD_RESP_DATA_ACCETPTED)
{
SPI_SendByte(0xFF);
/* 返回之前发送8个clock clock out 8 clk before return */
SPI_CS_Deassert();
return SD_ERR_DATA_RESP ;
/* 数据响应错误 data response error */
}
SPI_CS_Deassert();
if(SD_WaitBusy(SD_WAIT_WRITE)!=SD_NO_ERR)
return SD_ERR_TIMEOUT_WRITE ;
/* 写入超时 write time out */
else
return SD_NO_ERR ;
/* 写入正确 write right */
}
/*******************************************************************************
** 函数名称: void SD_StopMultiToken()
** 功能描述: 发送多块写停止令牌
** 输 入: 无
** 输 出: 无
*******************************************************************************/
void SD_StopMultiToken(void)
{
SPI_CS_Assert();
SPI_SendByte(0xFF);
/* 先发送8个clock send 8 clock first */
SPI_SendByte(SD_TOK_STOP_MULTI);
/* 发送停止数据传输令牌 send stop transmission token */
SPI_RecByte();
SPI_CS_Deassert();
}
/*******************************************************************************
** 函数名称: void SD_WaitBusy()
** 功能描述: 查询SD卡是否处于忙状态
** 输 入: INT32U waittype: 超时类型
** 输 出: 0: 未超时 >0: 错误码
*******************************************************************************/
INT8U SD_WaitBusy(INT8U waittype)
{
INT32U timeout,i=0 ;
INT8U tmp ;
if(waittype==SD_WAIT_WRITE)
timeout=sds.timeout_write ;
else
timeout=sds.timeout_erase ;
SPI_CS_Assert();
do
{
/* 等待忙结束 wait for being busy end */
tmp=SPI_RecByte();
i++;
}
while((tmp!=0xFF)&&(i<timeout));
/* 忙时收到的值为0xFF always receive 0xFF when card is busy */
SPI_CS_Deassert();
/* 有错 */
if(i<timeout)
return SD_NO_ERR ;
/* 返回0,表示没超时 return 0 indicate that operation is not time out */
else
return SD_ERR_TIMEOUT_WAIT ;
/* 返回错误码,表示超时 return error code indicate that operation is time out */
}
/*******************************************************************************
** 函数名称: void SD_SPIDelay()
** 功能描述: SPI总线延时
** 输 入: INT8U value: 延时值,不超过255
** 输 出: 无
*******************************************************************************/
void SD_SPIDelay(INT8U value)
{
INT8U i ;
for(i=0;i<value;i++)
SPI_SendByte(0xFF);
/* 发送0xFF clock out 0xFF */
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -