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

接下来就是实现文件系统,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

SD_Initialize
1 INT8U SD_Initialize(void)
2 {
3 INT8U recbuf[4],ret;
4 /* 创建访问SD/MMC卡信号量 create SD/MMC semaphore */
5  #if SD_UCOSII_EN
6 if (pSemSD == NULL)
7 {
8 pSemSD = OSSemCreate(1);
9 if (pSemSD == NULL)
10 return SD_ERR_CREATE_SEMSD;
11 }
12  #endif
13 /* 等待信号量 */
14 SD_StartSD();
15 /* 初始化读写SD卡的硬件条件 */
16 SD_HardWareInit();
17 /* 检查卡是否插入 */
18 if (SD_ChkCard() != 1)
19 {
20 ret = SD_ERR_NO_CARD;
21 goto SD_ERR;
22 }
23 /* 1. 置CS为低 */
24 SPI_CS_Assert();
25 /* 2. 至少延时 74 clock*/
26 SD_SPIDelay(25);
27 /* 3. 置CS为高 dessert CS */
28 SPI_CS_Deassert();
29 /* 4. 延时2(8 clock) delay 2(8 clock) */
30 SD_SPIDelay(2);
31 /* 5. 发出CMDO命令复位SD卡 */
32 ret = SD_ResetSD();
33 if (ret != SD_NO_ERR)
34 goto SD_ERR;
35 /* 6. 激活卡进入初始化过程 */
36 ret = SD_ActiveInit();
37 if (ret != SD_NO_ERR)
38 goto SD_ERR;
39 /* 7. 读OCR寄存器,查询卡支持的电压值 */
40 ret = SD_ReadOCR(4, recbuf);
41 if (ret != SD_NO_ERR)
42 goto SD_ERR;
43 /* 不支持3.3V,返回错误码 */
44 if ((recbuf[1] & MSK_OCR_33) != MSK_OCR_33)
45 {
46 ret = SD_ERR_VOL_NOTSUSP; goto SD_ERR;
47 }
48 /* 8. 设置SPI时钟到最大值 */
49 SPI_ClkToMax();
50 /* 使能CRC校验 */
51 #if SD_CRC_EN
52 ret = SD_EnableCRC(1);
53 if (ret != SD_NO_ERR)
54 goto SD_ERR;
55 #endif
56 /* 9. 设置块的长度: 512Bytes */
57 ret = SD_SetBlockLen(SD_BLOCKSIZE);
58 if (ret != SD_NO_ERR)
59 goto SD_ERR;
60 /* 10. 读CSD寄存器,获取SD卡信息 */
61 ret = SD_GetCardInfo();
62 if (ret != SD_NO_ERR)
63 goto SD_ERR;
64
65 SD_EndSD();
66 /* 初始化成功 initialize sucessfully */
67 return SD_NO_ERR;
68
69 SD_ERR:
70 SD_EndSD();
71 return ret;
72 }

2.SD_ReadBlock

SD_ReadBlock
1 INT8U SD_ReadBlock(INT32U blockaddr, INT8U *recbuf)
2 {
3 INT8U ret;
4 /* 向OS申请访问卡信号量 */
5 SD_StartSD();
6 if (SD_ChkCard() != 1)
7 {
8 SD_EndSD();
9 /* 卡没完全插入卡中 */
10 return SD_ERR_NO_CARD;
11 }
12
13 if (blockaddr > sds.block_num)
14 {
15 SD_EndSD();
16 /* 操作超出卡容量范围 */
17 return SD_ERR_OVER_CARDRANGE;
18 }
19 /* 读单块命令 */
20 ret = SD_ReadSingleBlock(blockaddr);
21 if (ret != SD_NO_ERR)
22 {
23 SD_EndSD();
24 return ret;
25 }
26 /* 读出数据 */
27 ret = SD_ReadBlockData(SD_BLOCKSIZE, recbuf);
28 /* 归还访问卡信号量 */
29 SD_EndSD();
30
31 return ret;
32 }

3.SD_WriteBlock

SD_WriteBlock
1 INT8U SD_WriteBlock(INT32U blockaddr, INT8U *sendbuf)
2 {
3 INT8U ret,tmp[2];
4 /* 向OS申请访问卡信号量 */
5 SD_StartSD();
6 if (SD_ChkCard() != 1)
7 {
8 SD_EndSD();
9 /* 卡没完全插入卡中 */
10 return SD_ERR_NO_CARD;
11 }
12
13 if (blockaddr > sds.block_num)
14 {
15 /* 操作超出卡容量范围 */
16 SD_EndSD();
17 return SD_ERR_OVER_CARDRANGE;
18 }
19
20 if (SD_ChkCardWP() == 1)
21 {
22 /* 卡有写保护 */
23 SD_EndSD();
24 return SD_ERR_WRITE_PROTECT;
25 }
26 /* 写单块命令 */
27 ret = SD_WriteSingleBlock(blockaddr);
28 if (ret != SD_NO_ERR)
29 {
30 SD_EndSD();
31 return ret;
32 }
33 /* 写入数据 */
34 ret = SD_WriteBlockData(0, SD_BLOCKSIZE, sendbuf);
35 /* 读Card Status寄存器, 检查写入是否成功 */
36 if (ret == SD_NO_ERR)
37 {
38 ret = SD_ReadCard_Status(2, tmp);
39 if (ret != SD_NO_ERR)
40 {
41 /* 读寄存器失败 */
42 SD_EndSD();
43 return ret;
44 }
45 if((tmp[0] != 0) || (tmp[1] != 0))
46 {
47 /* 响应指示写失败 */
48 SD_EndSD();
49 ret = SD_ERR_WRITE_BLK;
50 }
51 }
52 SD_EndSD();
53 /* 返回写入结果 */
54 return ret;
55 }

4.SD_ReadMultiBlock
   SD_WriteMultiBlock
处理流程与读写单个Block类似,就是多调用了SD_ReadMultipleBlock和SD_WriteMultipleBlock发送读写多个Block的命令,详细代码请参考上传的工程
5.SD_EraseBlock

SD_EraseBlock
1 INT8U SD_EraseBlock(INT32U startaddr, INT32U blocknum)
2 {
3 INT32 tmp;
4 INT8U ret;
5
6 SD_StartSD();
7 if (SD_ChkCard() != 1)
8 {
9 SD_EndSD();
10 return SD_ERR_NO_CARD;
11 }
12 if ((startaddr + blocknum) > sds.block_num)
13 {
14 SD_EndSD();
15 return SD_ERR_OVER_CARDRANGE;
16 }
17 if (SD_ChkCardWP() == 1)
18 {
19 SD_EndSD();
20 return SD_ERR_WRITE_PROTECT;
21 }
22
23 tmp = blocknum - sds.erase_unit;
24 /* 每次擦除扇区 */
25 while(tmp >= 0)
26 {
27 /* 选择起始块地址 */
28 ret = SD_EraseStartBlock(startaddr);
29 if (ret != SD_NO_ERR)
30 {
31 SD_EndSD();
32 return ret;
33 }
34 /* 选择终止块地址 */
35 ret = SD_EraseEndBlock(startaddr + sds.erase_unit - 1);
36 if (ret != SD_NO_ERR)
37 {
38 SD_EndSD();
39 return ret;
40 }
41 /* 擦除所选的块 */
42 ret = SD_EraseSelectedBlock();
43 if (ret != SD_NO_ERR)
44 {
45 SD_EndSD();
46 return ret;
47 }
48 /* 起始地址递增 */
49 startaddr += sds.erase_unit;
50 blocknum -= sds.erase_unit;
51 tmp = blocknum - sds.erase_unit;
52 };
53 /* 擦除不够once_erase块 */
54 if (blocknum > 0)
55 {
56 ret = SD_EraseStartBlock(startaddr);
57 if (ret != SD_NO_ERR)
58 {
59 SD_EndSD();
60 return ret;
61 }
62 ret = SD_EraseEndBlock(startaddr + blocknum - 1);
63 if (ret != SD_NO_ERR)
64 {
65 SD_EndSD();
66 return ret;
67 }
68 ret = SD_EraseSelectedBlock();
69 if (ret != SD_NO_ERR)
70 {
71 SD_EndSD();
72 return ret;
73 }
74 }
75 SD_EndSD();
76 return SD_NO_ERR;
77 }

6.SD_GetCardInfo

SD_GetCardInfo
1 INT8U SD_GetCardInfo()
2 {
3 INT32U tmp;
4 INT8U csdbuf[16],ret;
5 /* 读CSD寄存器 */
6 ret = SD_ReadCSD(16, csdbuf);
7 if (ret != SD_NO_ERR)
8 return ret;
9 /* 计算超时时间值 */
10 SD_CalTimeout(csdbuf);
11 /* 计算块的最大长度 */
12 sds.block_len = 1 << (csdbuf[READ_BL_LEN_POS] & READ_BL_LEN_MSK);/* (2 ^ READ_BL_LEN) */
13 /* 计算卡中块的个数 */
14 sds.block_num = ((csdbuf[C_SIZE_POS1] & C_SIZE_MSK1) << 10) +
15 (csdbuf[C_SIZE_POS2] << 2) +
16 ((csdbuf[C_SIZE_POS3] & C_SIZE_MSK3) >> 6) + 1;/* (C_SIZE + 1)*/
17 tmp = ((csdbuf[C_SIZE_MULT_POS1] & C_SIZE_MULT_MSK1) << 1) +
18 ((csdbuf[C_SIZE_MULT_POS2] & C_SIZE_MULT_MSK2) >> 7) + 2;/* (C_SIZE_MULT + 2) */
19 /* 获得卡中块的数量 */
20 sds.block_num = sds.block_num * (1 << tmp);/* (C_SIZE + 1) * 2 ^ (C_SIZE_MULT + 2) */
21 /* 计算擦除的单位(单位: 块) */
22 if (sds.card_type == CARDTYPE_MMC)
23 {
24 tmp = ((csdbuf[ERASE_GRP_SIZE_POS] & ERASE_GRP_SIZE_MSK) >> 2) + 1;/* (ERASE_GRP_SIZE + 1) */
25 /* (ERASE_GRP_SIZE + 1) * (ERASE_GRP_MULTI + 1) */
26 tmp *= ((csdbuf[ERASE_GRP_MULTI_POS1] & ERASE_GRP_MULTI_MSK1) << 3) +
27 ((csdbuf[ERASE_GRP_MULTI_POS2] & ERASE_GRP_MULTI_MSK2) >> 5) + 1;
28 }
29 else /*calculate the size of sector */
30 tmp = ((csdbuf[SECTOR_SIZE_POS1] & SECTOR_SIZE_MSK1) << 1) +
31 ((csdbuf[SECTOR_SIZE_POS2] & SECTOR_SIZE_MSK2) >> 7) + 1;/* SD: SECTOR_SIZE */
32 /* 擦除单位(块) */
33 sds.erase_unit = tmp;
34 return SD_NO_ERR;
35 }

读到的CSD对应数据的字节位置如下:

代码
1 #define TAAC_POS 1 //TACC
2 #define NSAC_POS 2 //NSAC
3
4 #define READ_BL_LEN_POS 5 //READ_BL_LEN
5
6 #define C_SIZE_POS1 6 //C_SIZE upper 2-bit
7 #define C_SIZE_POS2 7 //C_SIZE middle 8-bit
8 #define C_SIZE_POS3 8 //C_SIZE lower 2-bit
9
10 #define C_SIZE_MULT_POS1 9 //C_SIZE_MULT upper 2-bit
11 #define C_SIZE_MULT_POS2 10 //C_SIZE_MULT lower 1-bit
12
13 #define SECTOR_SIZE_POS1 10 //SECTOR_SIZE upper 5-bit
14 #define SECTOR_SIZE_POS2 11 //SECTOR_SIZE lower 2-bit
15
16 #define R2WFACTOR_POS 12 //R2WFACTOR_POS
17
18 #define ERASE_GRP_SIZE_POS 10 //MMC卡 ERASE_GRP_SIZE 5-bit
19 #define ERASE_GRP_MULTI_POS1 10 //MMC卡 ERASE_GRP_MULTI 2-bit
20 #define ERASE_GRP_MULTI_POS2 11 //MMC卡 ERASE_GRP_MULTI 3-bit

更底层的SD SPI命令实现请参考sdcmd.c,sdcmd.h,以下列举了一些SD命令:

代码
1 /* 设置块的长度 Set the block length */
2 #define CMD16 16
3 #define CMD16_R R1
4
5 /* 读单块 Read a single block */
6 #define CMD17 17
7 #define CMD17_R R1
8
9 /* 读多块,直至主机发送CMD12为止 Read multiple blocks until a CMD12 */
10 #define CMD18 18
11 #define CMD18_R R1
12 /* 写单块 Write a block of the size selected with CMD16 */
13 #define CMD24 24
14 #define CMD24_R R1
15
16 /* 写多块 Multiple block write until a CMD12 */
17 #define CMD25 25
18 #define CMD25_R R1

接下来介绍uCFS的在SD上的移植.

发表于 @ 2009年10月27日

posted on 2010-03-23 14:50  shevsten  阅读(569)  评论(0编辑  收藏  举报