📄 sd.c
字号:
fator = (csdbuf[R2WFACTOR_POS] & R2WFACTOR_MSK) >> 2; /* 读超时时间因数 read timeout factor */
if(time_v == 0) return SD_ERR_CARD_PARAM; /* 卡参数有错误 card parameter is error */
tmp = SPI_CLOCK * time_value[time_v] / 10 / time_unit[time_u]; /* TACC * f (单位 unit: clock) */
tmp = tmp + csdbuf[NSAC_POS] * 100; /* TACC * f + NSAC * 100 (单位 unit: clock) */
/* 计算得到的超时值 the timeout value of being calculated */
sds.timeout_read = tmp;
sds.timeout_write = tmp * r2w_fator[fator]; /* (TACC * f + NSAC * 100) * R2WFACTOR (单位 unit:clock)*/
if (sds.card_type == CARDTYPE_SD)
{
sds.timeout_read = sds.timeout_read * 100 / 8; /* 实际值为计算值的100倍 */
sds.timeout_write = sds.timeout_write * 100 / 8;
if (sds.timeout_read > READ_TIMEOUT_100MS) /* 取计算值与默认值中的最小值 */
sds.timeout_read = READ_TIMEOUT_100MS;
if (sds.timeout_write > WRITE_TIMEOUT_250MS)
sds.timeout_write = WRITE_TIMEOUT_250MS;
}
else
{
sds.timeout_read = sds.timeout_read * 10 / 8; /* 实际值为计算值的10倍 */
sds.timeout_write = sds.timeout_write * 10 / 8;
}
sds.timeout_erase = sds.timeout_write;
return SD_NO_ERR;
}
/*******************************************************************************************************************
** 函数名称: INT8U SD_GetCardInfo() Name: INT8U SD_GetCardInfo()
** 功能描述: 获得SD/MMC卡的信息 Function: get the information of SD/MMC card
** 输 入: INT8U cardtype: 卡类型 Input: INT8U cardtype: card type
** 输 出: 0: 成功 >0: 错误码 Output: 0: right >0: error code
*******************************************************************************************************************/
unsigned char SD_GetCardInfo(void)
{
unsigned int tmp;
unsigned char csdbuf[16],ret;
ret = SD_ReadCSD(16, csdbuf); /* 读CSD寄存器 read CSD register */
if (ret != SD_NO_ERR)
{
// Uart0_SendByte(0xa1);
return ret;
}
SD_CalTimeout(csdbuf); //计算读,写,擦时间
/* 计算块的最大长度 */ /* calculate the size of a sector */
sds.block_len = 1 << (csdbuf[READ_BL_LEN_POS] & READ_BL_LEN_MSK); /* (2 ^ READ_BL_LEN) */
// Uart0_SendByte(SD_BLOCKSIZE_NBITS);
// Uart1_SendByte(sds.block_len>>24);
// Uart1_SendByte(sds.block_len>>16);
// Uart1_SendByte(sds.block_len>>8);
// Uart1_SendByte(sds.block_len>>0);
//00 00 02 00 00 00 04 00
/* 计算卡中块的个数 */ /* calculate the sector numbers of the SD Card */
sds.block_num = ((csdbuf[C_SIZE_POS1] & C_SIZE_MSK1) << 10) +
(csdbuf[C_SIZE_POS2] << 2) +
((csdbuf[C_SIZE_POS3] & C_SIZE_MSK3) >> 6) + 1; /* (C_SIZE + 1)*/
tmp = ((csdbuf[C_SIZE_MULT_POS1] & C_SIZE_MULT_MSK1) << 1) +
((csdbuf[C_SIZE_MULT_POS2] & C_SIZE_MULT_MSK2) >> 7) + 2; /* (C_SIZE_MULT + 2) */
/* 获得卡中块的数量 */ /* get the block numbers in card */
sds.block_num = sds.block_num * (1 << tmp);
// Uart0_SendByte(sds.block_num>>24);
// Uart0_SendByte(sds.block_num>>16);
/// Uart0_SendByte(sds.block_num>>8);
// Uart0_SendByte(sds.block_num>>0);
// 00 07 8A 00 00 1E 4A 00
// 252,968,960 2,032,664,576
MAXBlock_num = sds.block_num;
/* 计算擦除的单位(单位: 块) */
if (sds.card_type == CARDTYPE_MMC)
{
tmp = ((csdbuf[ERASE_GRP_SIZE_POS] & ERASE_GRP_SIZE_MSK) >> 2) + 1; /* (ERASE_GRP_SIZE + 1) */
/* (ERASE_GRP_SIZE + 1) * (ERASE_GRP_MULTI + 1) */
tmp *= ((csdbuf[ERASE_GRP_MULTI_POS1] & ERASE_GRP_MULTI_MSK1) << 3) +
((csdbuf[ERASE_GRP_MULTI_POS2] & ERASE_GRP_MULTI_MSK2) >> 5) + 1;
}
else
{ /*calculate the size of sector */
tmp = ((csdbuf[SECTOR_SIZE_POS1] & SECTOR_SIZE_MSK1) << 1) +
((csdbuf[SECTOR_SIZE_POS2] & SECTOR_SIZE_MSK2) >> 7) + 1; /* SD: SECTOR_SIZE */
}
sds.erase_unit = tmp;
/* 擦除单位(块) */
// Uart0_SendByte(sds.erase_unit>>24);
// Uart0_SendByte(sds.erase_unit>>16);
// Uart0_SendByte(sds.erase_unit>>8);
// Uart0_SendByte(sds.erase_unit>>0);
// 00 00 00 20 00 00 00 20
return SD_NO_ERR;
}
/********************************************************************************************************************
** 函数名称: INT8U SD_BlockCommand() Name: INT8U SD_BlockCommand()
** 功能描述: 块命令 Function: command about block operation
** 输 入: INT8U cmd : 命令字 Input: INT8U cmd : command byte
INT8U resptype : 响应类型 INT8U resptype : response type
INT32U parameter: 块操作参数 INT32U parameter: parameter of block operation
** 输 出: 0: 正确 >0: 错误码 Output: 0: right >0: error code
*********************************************************************************************************************/
unsigned char SD_BlockCommand(unsigned char cmd, unsigned char resptype, unsigned int parameter)
{
unsigned char param[4],resp,ret;
parameter <<= SD_BLOCKSIZE_NBITS; /* 调整地址:左移9位 adjust address: move 9 bits left */
SD_PackParam(param, parameter); /* 将参数转化为字节形式 change the parameter to bytes form */
ret = SD_SendCmd(cmd, param, resptype, &resp);
if (ret != SD_NO_ERR)
{
return ret; /* 结束数据传输失败 stop transmission operation fail */
}
if (resp != 0)
{
return SD_ERR_CMD_RESP; /* 响应错误 response is error */
}
return SD_NO_ERR;
}
/********************************************************************************************************************
** 函数名称: INT8U SD_ReadSingleBlock() Name: INT8U SD_ReadSingleBlock()
** 功能描述: 读单块命令 Function: read single block command
** 输 入: INT32U blockaddr: 块地址 Input: INT32U blockaddr: block address
** 输 出: 0: 正确 >0: 错误码 Output: 0: right >0: error code
*********************************************************************************************************************/
unsigned char SD_ReadSingleBlock(unsigned int blockaddr)
{
return (SD_BlockCommand(CMD17, CMD17_R, blockaddr)); /* 读单块命令 command that read single block */
}
/*******************************************************************************************************************
** 函数名称: INT8U SD_ReadBlockData() Name: INT8U SD_ReadBlockData()
** 功能描述: 从卡中读取数据块 Function: read block data from card
** 输 入: INT32U len : 长度 Input: INT32U len : length
INT8U *recbuf : 接收缓冲区 INT8U *recbuf : the buffer of receive
** 输 出: 0: 正确 >0: 错误码 Output: 0: right >0: error code
*******************************************************************************************************************/
unsigned char SD_ReadBlockData(unsigned int len, unsigned char *recbuf)
{
unsigned char tmp;
unsigned int i = 0,timeout;
timeout = sds.timeout_read; /* 等待接收数据开始令牌最长时间 wait time that receive data start token */
SPI_CS_Assert();
do
{ /* 等待接收数据开始令牌0xFE wait for receiving data start token 0xFE */
tmp = SPI_RecByte();
i++;
}while((tmp == 0xFF) && (i < timeout));
if (i >= timeout)
{
SPI_CS_Deassert();
return SD_ERR_TIMEOUT_READ; /* 返回读超时错误码 return error timeout error code of reading */
}
if (tmp != SD_TOK_READ_STARTBLOCK) /* 块读开始令牌错误 read start block token is error */
{
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))
{
SPI_SendByte(0xFF); /* CRC校验错误 CRC check is error */
SPI_CS_Deassert();
return SD_ERR_DATA_CRC16; /* 返回RCR16错误 return error of CRC16 */
}
#endif
SPI_SendByte(0xFF);
SPI_CS_Deassert();
return SD_NO_ERR; /* 返回函数执行成功 return function perform sucessfully */
}
/****************************************************************************
** 函数名称: INT8U SD_WriteSingleBlock()
** 功能描述: 写单块命令
** 输 入: INT32U blockaddr: block address
** 输 出: 0: 正确 >0: 错误码
****************************************************************************/
unsigned char SD_WriteSingleBlock(unsigned int blockaddr)
{
return (SD_BlockCommand(CMD24, CMD24_R, blockaddr)); /* 写单块命令 command that write single block */
}
/**************************************************************************
** 函数名称: SD_WaitBusy()
** 功能描述: 查询SD卡是否处于忙状态
** 输 入: INT32U waittype: 超时类型
** 输 出: 0: 未超时 >0: 错误码
***************************************************************************/
unsigned char SD_WaitBusy(unsigned char waittype)
{
unsigned int timeout, i = 0;
unsigned char tmp;
if (waittype == SD_WAIT_WRITE)
{
timeout = sds.timeout_write; /* 等待类型为写操作 wait type is write operation */
}
else
{
timeout = sds.timeout_erase; /* 等待类型为擦除操作 wait type is erase operation */
}
SPI_CS_Assert();
do
{ /* 等待忙结束 wait for being busy end */
tmp = SPI_RecByte();
i++;
}while ((tmp != 0xFF) && (i < timeout)); /* 忙时收到的值为0 always receive 0 when card is busy */
if(i < timeout)
{
tmp = SD_NO_ERR; /* 返回0,表示没超时 return 0 indicate that operation is not time out */
}
else
{
tmp = SD_ERR_TIMEOUT_WAIT; /* 返回错误码,表示超时 return error code indicate that operation is time out */
}
SPI_SendByte(0xFF);
SPI_CS_Deassert();
return tmp; /* 返回执行结果 */
}
/****************************************************************************
** 函数名称: INT8U SD_ReadBlock()
** 功能描述: 从SD/MMC卡中读一个块
** 输 入: INT32U blockaddr: 块地址
INT8U *recbuf : 接收缓冲区,长度512Bytes
** 输 出: 0: 成功 >0: 错误码
******************************************************************************/
unsigned char SD_ReadBlock(unsigned int blockaddr, unsigned char *recbuf)
{
unsigned char ret;
if (SD_INSERT_STATUS())
{
return SD_ERR_NO_CARD; /* 卡没完全插入卡中 card is not inserted entirely */
}
if (blockaddr >= (sds.block_num*(sds.block_len/SD_BLOCKSIZE)))
{
return SD_ERR_OVER_CARDRANGE; /* 操作超出卡容量范围 operate over the card range */
}
ret = SD_ReadSingleBlock(blockaddr); /* 读单块命令 read single blocks command */
if (ret != SD_NO_ERR)
{
return ret;
}
ret = SD_ReadBlockData(SD_BLOCKSIZE, recbuf); /* 读出数据 read data from sd card */
return ret;
}
#include "../Uart1/Uart1.h"
/***************************************************************************
** 函数名称: INT8U SD_WriteBlockData()
** 功能描述: 向卡写数据块
** 输 入: INT8U bmulti : 是否为多块操作1:是0:否
INT32U len : 长度
INT8U *sendbuf: 发送缓冲区
** 输 出: 0: 正确 >0: 错误码
**************************************************************************/
unsigned char SD_WriteBlockData(unsigned char bmulti, unsigned int len, unsigned char *sendbuf)
{
unsigned short i;
unsigned char 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)
{
// Uart1_SendByte(tmp);
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 */
}
}
/************************************************************************
** 函数名称: INT8U SD_ReadCard_Status()
** 功能描述: 读SD/MMC卡的 Card Status 寄存器
** 输 入: INT8U len: 寄存器长度(固定为2)
INT8U *recbuf : 接收缓冲区
** 输 出: 0: 正确 >0: 错误码
*************************************************************************/
unsigned char SD_ReadCard_Status(unsigned int len, unsigned char *buffer)
{
unsigned char param[4] = {0,0,0,0};
return (SD_SendCmd(CMD13, param, CMD13_R, buffer)); /* 读 Card Status 寄存器 */
/* read register of Card Status */
}
/************************************************************************
** 函数名称: EfficacyData()
** 功能描述: SD卡数据效验
** 输 入: blockaddr: 块地址
Data 数据指针
** 输 出: 0: 正确 >0: 错误码
*************************************************************************/
unsigned char EfficacyData(unsigned int blockaddr, unsigned char *sendbuf)
{
unsigned int i,j;
unsigned char c1,c2;
unsigned char tmp;
c1 = 0 ;
for( i = 0 ; i < SD_BLOCKSIZE ; i++ )
{
c1 += sendbuf[i];
}
for( j = 0 ; j < 10 ; j++ )
{
tmp = SD_ReadBlock(blockaddr,sendbuf);
if(tmp == SD_NO_ERR)
{
break;
}
}
if(j>=10)
{
return SD_READ_ERR;
}
c2 = 0 ;
for( i = 0 ; i < SD_BLOCKSIZE ; i++ )
{
c2 += sendbuf[i];
}
if(c1==c2)
{
return SD_NO_ERR;
}
else
{
return SD_Efficacy_ERR;
}
}
/****************************************************************************
** 函数名称: INT8U SD_WriteBlock()
** 功能描述: 向SD/MMC卡中写入一个块
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -