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
2.SD_ReadBlock
3.SD_WriteBlock
4.SD_ReadMultiBlock
SD_WriteMultiBlock
处理流程与读写单个Block类似,就是多调用了SD_ReadMultipleBlock和SD_WriteMultipleBlock发送读写多个Block的命令,详细代码请参考上传的工程
5.SD_EraseBlock
6.SD_GetCardInfo
读到的CSD对应数据的字节位置如下:
更底层的SD SPI命令实现请参考sdcmd.c,sdcmd.h,以下列举了一些SD命令:
接下来介绍uCFS的在SD上的移植.
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上的移植.
相关文章推荐
- SMARTARM2200 ADS工程在IAR EWARM 5.3上的移植(8)-LwIP 1.2的移植(RTL8019AS驱动2)
- SMARTARM2200 ADS工程在IAR EWARM 5.3上的移植(10)-uCFS的移植(uCFS在SD上的移植)
- SMARTARM2200 ADS工程在IAR EWARM 5.3上的移植(7)-LwIP 1.2的移植(RTL8019AS驱动1)
- SMARTARM2200 ADS工程在IAR EWARM 5.3上的移植(6)-LwIP 1.2的移植(uCOSII部分)
- SMARTARM2200 ADS工程在IAR EWARM 5.3上的移植(1)-启动代码(cstartup.s)分析
- SMARTARM2200 ADS工程在IAR EWARM 5.3上的移植(4)-printf的串口实现
- SMARTARM2200 ADS工程在IAR EWARM 5.3上的移植(3)-IAR Linker文件分析
- SMARTARM2200 ADS工程在IAR EWARM 5.3上的移植(1)-启动代码(cstartup.s)分析
- SMARTARM2200 ADS工程在IAR EWARM 5.3上的移植(5)-ZLG-TCPIP的移植
- SMARTARM2200 ADS工程在IAR EWARM 5.3上的移植(1)-启动代码(cstartup.s)分析
- SMARTARM2200 ADS工程在IAR EWARM 5.3上的移植(2)-uCOSII移植代码分析
- Linux-2.6.30.4在2440上的移植之MMC/SD卡驱动
- linux-2.6.32在mini2440开发板上移植---SD卡驱动移植
- DM9000 驱动移植及源码简析
- Linux-2.6.32.2内核在mini2440上的移植(十一)---移植SD卡驱动
- mini2440上一步步实现将ADS工程移植到keil MDK(附移植好的完整代码)
- 【TINY4412】U-BOOT移植笔记:(8)SD卡驱动
- Linux-2.6.32.2内核在mini2440上的移植(十一)---移植SD卡驱动
- S3C2440 Linux驱动移植——SD卡驱动
- stm32移植ecos,ecos sd driver,SD卡驱动