📄 sddriver.c
字号:
{
U8 i;
for (i = 0; i < value; i++)
SPI_TxBYTE(0xFF); /* 发送0xFF */
}
//=============================================================================================
#if SD_FreeRTOS_EN
xSemaphoreHandle pSemSD = NULL; /* 卡访问权限信号量 semaphore that access card */
#endif
/* SD卡信息结构体变量 the information structure variable of SD Card */
sd_struct sds;
/* 超时时间单位表(单位:0.000000001ns) timeout unit table */
const U32 time_unit[8] = {1000000000,100000000,10000000,
1000000,100000,10000,1000,100};
/* 超时时间表 timeout value table */
const U8 time_value[16] = {0,10,12,13,15,20,25,30,
35,40,45,50,55,60,70,80};
/* 超时时间因数表 timeout factor table */
const U8 r2w_fator[8] = {1,2,4,8,16,32,64,128};
// 初始化SD/MMC卡 0: 成功,X:错误码
U8 SD_Initialize(void)
{
U8 recbuf[4],ret;
#if SD_FreeRTOS_EN
if (pSemSD == NULL)
{
/* 创建访问SD/MMC卡信号量 create SD/MMC semaphore */
pSemSD = xSemaphoreCreateMutex();
if (pSemSD == NULL)
return SD_ERR_CREATE_SEMSD;
}
#endif
SD_StartSD();
SD_HardWareInit(); /* 初始化读写SD卡的硬件条件*/
if (SD_ChkCard_IN() != 1) /* 检查卡是否插入 */
{
ret = SD_ERR_NO_CARD;
goto SD_ERR;
}
SPI_CS_Enable(); /* 1. 置CS为低*/
SD_SPIDelay(25); /* 2. 至少延时 74 clock */
SPI_CS_Disable(); /* 3. 置CS为高 */
SD_SPIDelay(2); /* 4. 延时2(8 clock)*/
ret = SD_ResetSD(); /* 5. 发出CMDO命令复位SD卡*/
if (ret != SD_NO_ERR)
goto SD_ERR;
ret = SD_ActiveInit(); /* 6. 激活卡进入初始化过程. */
if (ret != SD_NO_ERR)
goto SD_ERR;
ret = SD_ReadOCR(4, recbuf);/* 7. 读OCR寄存器,查询卡支持的电压值 */
if (ret != SD_NO_ERR)
goto SD_ERR;
if ((recbuf[1] & MSK_OCR_33) != MSK_OCR_33)
{
ret = SD_ERR_VOL_NOTSUSP; /* 不支持3.3V,返回错误码 */
goto SD_ERR;
}
ret = SD_SetBlockLen(SD_BLOCKSIZE); /* 9. 设置块的长度: 512Bytes */
if (ret != SD_NO_ERR)
goto SD_ERR;
ret = SD_GetCardInfo(); /* 10. 读CSD寄存器,获取SD卡信息 */
if (ret != SD_NO_ERR)
goto SD_ERR;
SD_EndSD();
return SD_NO_ERR; /* 初始化成功 */
SD_ERR:
SD_EndSD();
return ret;
}
// 从SD/MMC卡中读一个块 (块地址,缓冲区-512字节) 0: 成功,X:错误码
U8 SD_ReadBlock(U32 blockaddr, U8 *recbuf)
{
U8 ret;
SD_StartSD(); /* 向OS申请访问卡信号量 */
if (SD_ChkCard_IN() != 1)
{
SD_EndSD();
return SD_ERR_NO_CARD; /* 卡没完全插入卡中*/
}
if (blockaddr > sds.block_num)
{
SD_EndSD();
return SD_ERR_OVER_CARDRANGE; /* 操作超出卡容量范围 */
}
ret = SD_BlockCMD(CMD17, CMD17_R, blockaddr);/* 读单块命令 */
if (ret != SD_NO_ERR)
{
SD_EndSD();
return ret;
}
ret = SD_ReadBlockData(SD_BLOCKSIZE, recbuf); /* 读出数据 */
SD_EndSD(); /* 归还访问卡信号量 */
return ret;
}
// 向SD/MMC卡中写入一个块 (块地址,缓冲区-512字节) 0: 成功,X:错误码
U8 SD_WriteBlock(U32 blockaddr, U8 *sendbuf)
{
U8 ret,tmp[2];
SD_StartSD(); /* 向OS申请访问卡信号量*/
if (SD_ChkCard_IN() != 1)
{
SD_EndSD();
return SD_ERR_NO_CARD; /* 卡没完全插入卡中 */
}
if (blockaddr > sds.block_num)
{
SD_EndSD();
return SD_ERR_OVER_CARDRANGE;/* 操作超出卡容量范围 */
}
if (SD_ChkCard_WP() == 1)
{
SD_EndSD();
return SD_ERR_WRITE_PROTECT; /* 卡有写保护 */
}
ret = SD_BlockCMD(CMD24, CMD24_R, blockaddr); /* 写单块命令 */
if (ret != SD_NO_ERR)
{
SD_EndSD();
return ret;
}
ret = SD_WriteBlockData(0, SD_BLOCKSIZE, sendbuf);/* 写入数据*/
if (ret == SD_NO_ERR) /* 读Card Status寄存器, 检查写入是否成功 */
{
ret = SD_ReadCard_Status(2, tmp);
if (ret != SD_NO_ERR)
{
SD_EndSD();
return ret; /* 读寄存器失败*/
}
if((tmp[0] != 0) || (tmp[1] != 0))
{
SD_EndSD();
ret = SD_ERR_WRITE_BLK; /* 响应指示写失败*/
}
}
SD_EndSD();
return ret; /* 返回写入结果 */
}
/*****************************************************************
下面为子程序
*****************************************************************/
// 获得SD/MMC卡的信息 0: 成功 >0:错误码
U8 SD_GetCardInfo()
{
U32 tmp;
U8 csdbuf[16],ret;
ret = SD_ReadCSD(16, csdbuf); /* read CSD register */
if (ret != SD_NO_ERR)
return ret;
SD_CalTimeout(csdbuf); /* calculate timeout value */
/* 计算块的最大长度 calculate the size of a sector */
sds.block_len = 1 << (csdbuf[READ_BL_LEN_POS] & READ_BL_LEN_MSK); /* (2 ^ READ_BL_LEN) */
/* 计算卡中块的个数 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); /* (C_SIZE + 1) * 2 ^ (C_SIZE_MULT + 2) */
/* 计算擦除的单位(单位: 块) */
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; /* 擦除单位(块) */
return SD_NO_ERR; /* perform sucessfully */
}
/*******************************************************************************************************************
** 函数名称: U8 SD_CalTimeout()
** 功能描述: 计算读/写/擦超时时间
** 输 入: U8 *csdbuf : CSD寄存器内容
** 输 出: 0: 成功 >0: 错误码
*******************************************************************************************************************/
U8 SD_CalTimeout(U8 *csdbuf)
{
U32 tmp;
U8 time_u,time_v,fator;
sds.timeout_read = READ_TIMEOUT_100MS; /* 默认读超时为100ms */
sds.timeout_write = WRITE_TIMEOUT_250MS; /* 默认写超时为250ms */
sds.timeout_erase = WRITE_TIMEOUT_250MS;
time_u = (csdbuf[TAAC_POS] & TAAC_MSK); /* 读超时时间单位 */
time_v = (csdbuf[TAAC_POS] & NSAC_MSK) >> 3; /* 读超时时间值 */
fator = (csdbuf[R2WFACTOR_POS] & R2WFACTOR_MSK) >> 2; /* 读超时时间因数 */
if(time_v == 0) return SD_ERR_CARD_PARAM; /* 卡参数有错误*/
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;
#if SD_FreeRTOS_EN
sds.timeout_read = (sds.timeout_read << 3) * configTICK_RATE_HZ / SPI_CLOCK;
sds.timeout_write =(sds.timeout_write << 3) * configTICK_RATE_HZ / SPI_CLOCK;
sds.timeout_erase = sds.timeout_write; /* (单位 unit: os tick) */
#endif
return SD_NO_ERR;
}
/*******************************************************************************************************************
** 函数名称: U8 SD_ActiveInit()
** 功能描述: 激活卡,并获得卡型
** 输 入: 无
** 输 出: 0: 成功 >0: 错误码
** 函数说明: 该命令不断重复发送到SD卡,直到响应R1的Bit0(Idle)位为0,表示SD卡内部初始化处理完成。
当响应的Idle位为0时,SD卡就完全进入SPI模式了。当然重复发送命令CMD1是有次数限制的,
最大次数为宏定义SD_IDLE_WAIT_MAX.
*******************************************************************************************************************/
U8 SD_ActiveInit(void)
{
U8 param[4] = {0,0,0,0},resp[5],ret;
U32 i = 0;
do
{ /* 发出CMD1, 查询卡的状态, send CMD1 to poll card status */
ret = SD_TxCMD(CMD1, param, CMD1_R, resp);
if (ret != SD_NO_ERR)
return ret;
i ++;
}while (((resp[0] & MSK_IDLE) == MSK_IDLE) && (i <= SD_IDLE_WAIT_MAX));
/* 如果响应R1的最低位Idle位为1,则继续循环 */
/* if response R1 Idle bit is 1,continue recycle */
if (i >= SD_IDLE_WAIT_MAX)
return SD_ERR_TIMEOUT_WAITIDLE; /* 超时,返回错误 time out,return error */
ret = SD_TxCMD(CMD55, param, CMD55_R, resp);
if (ret != SD_NO_ERR)
return ret;
ret = SD_TxCMD(ACMD41, param, ACMD41_R, resp); /* 激活内部初始化命令 active card to initialize process internal */
if (ret != SD_NO_ERR)
return SD_ERR_UNKNOWN_CARD;
if ((resp[0] & 0xFE) == 0)
sds.card_type = CARDTYPE_SD; /* 是SD卡 the card is SD card */
else
sds.card_type = CARDTYPE_MMC; /* 是MMC卡 the card is MMC card */
return SD_NO_ERR;
}
// 向操作系统申请访问SD卡的权限
void SD_StartSD(void)
{
#if SD_FreeRTOS_EN
/* 等待访问卡信号量可用 wait for semaphore that accessed Card */
xQueueTakeMutexRecursive(pSemSD,(portTickType)10);
#endif
}
// 访问SD卡的权限归还操作系统
void SD_EndSD(void)
{
#if SD_FreeRTOS_EN
/* 将访问卡信号量还给操作系统 return the semaphore accessing Card to OS */
xQueueGiveMutexRecursive(pSemSD);
#endif
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -