最近在负责SD卡驱动的开发移植工作,支持vfat文件系统,现在谈一下开发心得吧!
SD卡高度集成闪存,具备串行和随机存取能力。可以通过专用优化速度的串行接口访问,数据传输可靠。接口允许几个卡垛叠,通过他们的外部连接。接口完全符合最新的消费者标准,叫做SD卡系统标准,由SD卡系统规范定义。 SD卡系统是一个新的大容量存储系统,基于半导体技术的变革。它的出现,提供了一个便宜的、结实的卡片式的存储媒介,为了消费多媒体应用。SD卡可以设计出便宜的播放器和驱动器而没有可移动的部分。一个低耗电和广供电电压的可以满足移动电话、电池应用比如音乐播放器、个人管理器、掌上电脑、电子书、电子百科全书、电子词典等等。
一、SD Bus Protocol
SD总线有两种SD Bus和SPI Bus。笔者以SD Bus为例:
SD Bus由CLK,CMD,DAT0-3,VDD,VSS组成。SD bus模式下的命令和数据流都有一个起始位和一个停止位。命令格式固定为48bits,(start bit 固定为‘0’)+ (transmitter bit为‘1’)+(command & address or parameter)+(CRC7)+(end bit '1')。
而响应格式有两种,看命令响应的类型,R1,R3,R6的响应格式为,(start bit 固定为‘0’)+ (transmitter bit为‘0’)+(command & status(R1),OCR(R3)or RCA(R6))+(CRC7)+(end bit '1')。R2的响应格式为,(start bit 固定为‘0’)+ (transmitter bit为‘0’)+(CID or CSD))+(CRC7)+(end bit '1')。
二、SD卡初始化处理
首先初始化一下controller,比如fifo,dma模式,enbale位等。初始化好了controller后,需要设置一下啊通讯时钟,设好后就可以去跟SD memory card去做沟通了。这个过程都是通过发送CMD来完成的,首先读取controller的detect寄存器,看有没有卡插入,有插入的情况下才发送CMD0去reset card to idle state,再发送CMD8,把controller提供的电压信息和check pattern发送给SD卡,这一步成功就可以发送ACMD41去获取SD OCR信息,这一步需要把controller的capacity support info和要求SD发送它的OCR给controller,这一步成功后,就可以接着发送CMD2去读SD的CID信息,再发CMD3去读SD卡的RCA,再发CMD9去读SD卡的CSD,这个很重要,卡的容量信息在这里面,再设置通讯bus的宽带,有1线跟4线的区别,最后把CLK设置高一些,可以为25MHZ,这样读数据就快很多。到此为止,卡的初始化工作已经完成,可以进行读写。
三、如何判断SD卡是standard SD card还是high capacity SD card
在初始化过程中,发送ACMD41后,获取的SD OCR寄存器信息,在它的第30bit也就是CCS(card capacity status),如果该位为1,则表明是high capacity SD card,为0的话就是standard SD card。
四、SD信息注册给VFAT
由于需要读取SD卡中vfat文件系统中的文件,因此我们需要把SD卡read操作函数指针、设备类型、容量信息、CID信息注册给fat部分。就是这个结构static block_dev_desc_t mmc_blk_dev = {0};
mmc_blk_dev.if_type = IF_TYPE_MMC;
mmc_blk_dev.part_type = PART_TYPE_DOS;
mmc_blk_dev.dev = 0;
mmc_blk_dev.lun = 0;
mmc_blk_dev.type = 0;
mmc_blk_dev.blksz = STORAGE_BLOCK_SIZE;
/*mmc_blk_dev.lba = 0x400000; get from CSD info */
mmc_blk_dev.removable = 0;
mmc_blk_dev.block_read = mmc_block_read;
ret = fat_register_device(&mmc_blk_dev, 1);
把该结构填好后,调用fat_register_device(&mmc_blk_dev, 1)注册。
五、uboot下FAT
uboot下支持fat12、16、32。在 fat_register_device这个接口中有一个bug,用mkdosfs格式化的SD卡,其生成的MBR信息跟在PC上不一样。fat.c中的代码片段&buffer[DOS_FS_TYPE_OFFSET]起始的3个字节数据是否为“FAT”来判断其文件系统是不是FAT格式的,DOS_FS_TYPE_OFFSET为0x36,但是用mkdosfs格式化的SD卡,其生成的MBR信息,其"FAT"描述在偏移0x52处,所以在fat_register_device()接口中需要做兼容性调整。这个小bug可以从static int
read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize)这个接口的实现里看出。在这个
read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize)接口中已经做了兼容,在boot sector中fat_length,如果为0的话,就做了增加偏移量,用mkdosfs格式化的SD卡,其生成的MBR信息中fat_length恰恰为0.
六、总结
SD卡驱动开发并不复杂,在写代码之前先把SD卡协议搞清楚,再把controller的寄存器意思搞明白,就可以动手干活了。调试是痛苦滴,SD work成功了,也会带来一丝喜悦!