您的位置:首页 > 其它

SMARTARM2200 ADS工程在IAR EWARM 5.3上的移植(9)-uCFS的移植(SD卡驱动简析)

2009-10-27 13:20 381 查看
接下来就是实现文件系统,uCFS在SD卡上的移植.我用的还是1.34.01版本,网上到处都是.不过更高版本的很难找到,谁有的愿与我分享会非常感谢.
SMARTARM2200上SD卡通过SPI与处理器通信,另外3根IO用来控制供电,插入检测,写保护检测.SD驱动代码从ZLG的工程中获得用来移植到IAR上.移植好的工程请见http://download.csdn.net/source/1796291大部分代码来源于网络,我做了些整合和修改.
SD驱动共有9个文件:
1.sdconfig.h
定义了一些宏,包括配置参数及初始化SPI/SD引脚
2.sdhal.c,sdhal.h
SD卡底层的处理函数,如果电源初始化,SPI初始化,设置SPI时钟,SPI读写函数,SD卡检测
3.sdcmd.c,sdcmd.h
SD命令函数
4.sdcrc.c,sdcrc.h
CRC校验
5.sddriver.c,sddriver.h
SD较高层的驱动,如SD初始化,读写SD Block函数

接下来就sddriver.c中的一些代码进行简要分析.
1.SD_Initialize
INT8U SD_Initialize(void)
{
INT8U recbuf[4],ret;
/* 创建访问SD/MMC卡信号量 create SD/MMC semaphore */
#if SD_UCOSII_EN
if (pSemSD == NULL)
{
pSemSD = OSSemCreate(1);
if (pSemSD == NULL)
return SD_ERR_CREATE_SEMSD;
}
#endif
/* 等待信号量 */
SD_StartSD();
/* 初始化读写SD卡的硬件条件 */
SD_HardWareInit();
/* 检查卡是否插入 */
if (SD_ChkCard() != 1)
{
ret = SD_ERR_NO_CARD;
goto SD_ERR;
}
/* 1. 置CS为低 */
SPI_CS_Assert();
/* 2. 至少延时 74 clock*/
SD_SPIDelay(25);
/* 3. 置CS为高 dessert CS */
SPI_CS_Deassert();
/* 4. 延时2(8 clock) delay 2(8 clock) */
SD_SPIDelay(2);
/* 5. 发出CMDO命令复位SD卡 */
ret = SD_ResetSD();
if (ret != SD_NO_ERR)
goto SD_ERR;
/* 6. 激活卡进入初始化过程 */
ret = SD_ActiveInit();
if (ret != SD_NO_ERR)
goto SD_ERR;
/* 7. 读OCR寄存器,查询卡支持的电压值  */
ret = SD_ReadOCR(4, recbuf);
if (ret != SD_NO_ERR)
goto SD_ERR;
/* 不支持3.3V,返回错误码   */
if ((recbuf[1] & MSK_OCR_33) != MSK_OCR_33)
{
ret = SD_ERR_VOL_NOTSUSP;			goto SD_ERR;
}
/* 8. 设置SPI时钟到最大值 */
SPI_ClkToMax();
/* 使能CRC校验 */
#if SD_CRC_EN
ret = SD_EnableCRC(1);
if (ret != SD_NO_ERR)
goto SD_ERR;
#endif
/* 9. 设置块的长度: 512Bytes  */
ret = SD_SetBlockLen(SD_BLOCKSIZE);
if (ret != SD_NO_ERR)
goto SD_ERR;
/* 10. 读CSD寄存器,获取SD卡信息 */
ret = SD_GetCardInfo();
if (ret != SD_NO_ERR)
goto SD_ERR;

SD_EndSD();
/* 初始化成功 initialize sucessfully */
return SD_NO_ERR;

SD_ERR:
SD_EndSD();
return ret;
}

2.SD_ReadBlock
INT8U SD_ReadBlock(INT32U blockaddr, INT8U *recbuf)
{
INT8U ret;
/* 向OS申请访问卡信号量 */
SD_StartSD();
if (SD_ChkCard() != 1)
{
SD_EndSD();
/* 卡没完全插入卡中 */
return SD_ERR_NO_CARD;
}

if (blockaddr > sds.block_num)
{
SD_EndSD();
/* 操作超出卡容量范围 */
return SD_ERR_OVER_CARDRANGE;
}
/* 读单块命令 */
ret = SD_ReadSingleBlock(blockaddr);
if (ret != SD_NO_ERR)
{
SD_EndSD();
return ret;
}
/* 读出数据 */
ret = SD_ReadBlockData(SD_BLOCKSIZE, recbuf);
/* 归还访问卡信号量 */
SD_EndSD();

return ret;
}

3.SD_WriteBlock
INT8U SD_WriteBlock(INT32U blockaddr, INT8U *sendbuf)
{
INT8U ret,tmp[2];
/* 向OS申请访问卡信号量 */
SD_StartSD();
if (SD_ChkCard() != 1)
{
SD_EndSD();
/* 卡没完全插入卡中 */
return SD_ERR_NO_CARD;
}

if (blockaddr > sds.block_num)
{
/* 操作超出卡容量范围 */
SD_EndSD();
return SD_ERR_OVER_CARDRANGE;
}

if (SD_ChkCardWP() == 1)
{
/* 卡有写保护 */
SD_EndSD();
return SD_ERR_WRITE_PROTECT;
}
/* 写单块命令 */
ret = SD_WriteSingleBlock(blockaddr);
if (ret != SD_NO_ERR)
{
SD_EndSD();
return ret;
}
/* 写入数据 */
ret = SD_WriteBlockData(0, SD_BLOCKSIZE, sendbuf);
/* 读Card Status寄存器, 检查写入是否成功 */
if (ret == SD_NO_ERR)
{
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;
}


4.SD_ReadMultiBlock
SD_WriteMultiBlock
处理流程与读写单个Block类似,就是多调用了SD_ReadMultipleBlock和SD_WriteMultipleBlock发送读写多个Block的命令,详细代码请参考上传的工程
5.SD_EraseBlock
INT8U SD_EraseBlock(INT32U startaddr, INT32U blocknum)
{
INT32 tmp;
INT8U ret;

SD_StartSD();
if (SD_ChkCard() != 1)
{
SD_EndSD();
return SD_ERR_NO_CARD;
}
if ((startaddr + blocknum) > sds.block_num)
{
SD_EndSD();
return SD_ERR_OVER_CARDRANGE;
}
if (SD_ChkCardWP() == 1)
{
SD_EndSD();
return SD_ERR_WRITE_PROTECT;
}

tmp = blocknum - sds.erase_unit;
/* 每次擦除扇区 */
while(tmp >= 0)
{
/* 选择起始块地址 */
ret = SD_EraseStartBlock(startaddr);
if (ret != SD_NO_ERR)
{
SD_EndSD();
return ret;
}
/* 选择终止块地址 */
ret = SD_EraseEndBlock(startaddr + sds.erase_unit - 1);
if (ret != SD_NO_ERR)
{
SD_EndSD();
return ret;
}
/* 擦除所选的块 */
ret = SD_EraseSelectedBlock();
if (ret != SD_NO_ERR)
{
SD_EndSD();
return ret;
}
/* 起始地址递增 */
startaddr += sds.erase_unit;
blocknum  -= sds.erase_unit;
tmp = blocknum - sds.erase_unit;
};
/* 擦除不够once_erase块 */
if (blocknum > 0)
{
ret = SD_EraseStartBlock(startaddr);
if (ret != SD_NO_ERR)
{
SD_EndSD();
return ret;
}
ret = SD_EraseEndBlock(startaddr + blocknum - 1);
if (ret != SD_NO_ERR)
{
SD_EndSD();
return ret;
}
ret = SD_EraseSelectedBlock();
if (ret != SD_NO_ERR)
{
SD_EndSD();
return ret;
}
}
SD_EndSD();
return SD_NO_ERR;
}

6.SD_GetCardInfo
INT8U SD_GetCardInfo()
{
INT32U tmp;
INT8U csdbuf[16],ret;
/* 读CSD寄存器  */
ret = SD_ReadCSD(16, csdbuf);
if (ret != SD_NO_ERR)
return ret;
/* 计算超时时间值 */
SD_CalTimeout(csdbuf);
/* 计算块的最大长度  */
sds.block_len = 1 << (csdbuf[READ_BL_LEN_POS] & READ_BL_LEN_MSK);/* (2 ^ READ_BL_LEN) */
/* 计算卡中块的个数 */
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) */
/* 获得卡中块的数量 */
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;
}

读到的CSD对应数据的字节位置如下:
#define TAAC_POS 			1			//TACC
#define NSAC_POS			2			//NSAC

#define READ_BL_LEN_POS		5			//READ_BL_LEN

#define C_SIZE_POS1			6			//C_SIZE upper  2-bit
#define C_SIZE_POS2			7			//C_SIZE middle 8-bit
#define C_SIZE_POS3			8			//C_SIZE lower	2-bit

#define C_SIZE_MULT_POS1	9			//C_SIZE_MULT upper 2-bit
#define C_SIZE_MULT_POS2	10			//C_SIZE_MULT lower 1-bit

#define SECTOR_SIZE_POS1	10			//SECTOR_SIZE upper 5-bit
#define SECTOR_SIZE_POS2	11			//SECTOR_SIZE lower 2-bit

#define R2WFACTOR_POS 		12			//R2WFACTOR_POS

#define ERASE_GRP_SIZE_POS   	10		//MMC卡 ERASE_GRP_SIZE 5-bit
#define ERASE_GRP_MULTI_POS1 	10		//MMC卡 ERASE_GRP_MULTI 2-bit
#define ERASE_GRP_MULTI_POS2 	11		//MMC卡 ERASE_GRP_MULTI 3-bit

更底层的SD SPI命令实现请参考sdcmd.c,sdcmd.h,以下列举了一些SD命令:
/* 设置块的长度 Set the block length */
#define CMD16 16
#define CMD16_R R1

/* 读单块 Read a single block */
#define CMD17 17
#define CMD17_R R1

/* 读多块,直至主机发送CMD12为止 Read multiple blocks until a CMD12 */
#define CMD18 18
#define CMD18_R R1
/* 写单块 Write a block of the size selected with CMD16 */
#define CMD24 24
#define CMD24_R R1

/* 写多块 Multiple block write until a CMD12 */
#define CMD25 25
#define CMD25_R R1

接下来介绍uCFS的在SD上的移植.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: