目录
1.硬件设计 |
3.系统测试及结果 |
结束语 |
近年来,以Flash为存储体的SD卡因其具备体积小、功耗低、可擦写以及非易失性等特点而被广泛应用于消费类电子产品中。在SD卡存储器的设计中,利用文件系统对存储媒介进行管理已成为嵌入式系统的一个发展方向,因此需要一种可靠的文件系统,本文提出了一种基于FatFs文件系统的SD卡存储器设计,采用了开源文件系统FatFsR0.07C。FatFs是一种免费开源的FAT文件系统模块,专门为嵌入式系统而设计。它完全用标准C语言编写,具有良好的硬件平台独立性,经过简单的修改就可以移植到多种嵌入式处理器上。系统以ST公司的STM32F103R为核心,通过SPI总线与SD卡进行通信,实现了数据的便携式存储。给出了系统的硬件结构图,详细探讨了SD卡驱动程序以及FatFs移植方面的软件设计。
SD卡具有两种通信模式:SD模式和SPI模式。由于多数嵌入式处理器都配有SPI接口,因此相对于SD模式,SPI模式应用的更广泛一些。本设计采用STM32F103R对SD卡进行控制,STM32F103R是ST公司的一款基于ARMCoutex.M3的微控制器,该控制器片内设备丰富,处理速度快,性能稳定,其与SD卡的接口电路图如图1所示。
图1 STM32F103R与SD卡的接口电路图
本系统的软件设计是基于FatFs文件系统的。FatFs具有非常清晰的层次结构,如图2所示。最顶层是应用层,这一层为用户提供了一系列API函数,如f_open、f_close、f_read、f_write等,用户即使不理解Fat协议,也可以利用API函数轻松地读/写文件。中间层FatFsModule完整地实现了Fat协议,用户无需对此进行任何修改。最底层是用户在移植过程需要处理的接口,包括存储媒介读/写接口DisklO和文件创建修改时间时所需的实时时钟,用户根据具体的硬件编写程序,填充相关函数,即可使FatFs文件系统应用在具体的嵌入式平台设备上。
图2 FatFs结构图
根据层次式软件设计的思想,将软件设计工作分为3步:编写SD卡的通信函数、编写RTC时钟函数和FatFs的移植。
将SD卡通信函数分为3层,如图3所示。
图3 SD卡通信结构软件结构图
(1)SPI接口函数
SPI接口函数是与处理器相关的代码,这里的处理器是STM32F103R,主要包含SPI模式的配置以及SPI单字节的读写函数。
(2)SD卡底层接口函数
SD卡底层接口函数主要包含SD卡写命令和读数据等函数,按照标准的时序调用SPI接口函数即可。
(3)SD卡高级接口函数
SD卡高级函数依据SD卡通信协议V2.0编写,需要SPI接口函数以及SD卡底层接口函数的支持。这部分主要是SD卡的初始化函数和扇区读/写函数,此外还有一些用来读SD卡信息(厂商,容量,速度等)的函数。初始化工作是SD卡驱动程序编写的一个难点,这里给出详细的流程图(如图4所示),扇区读/写函数结构图如图5和图6所示。
图4 SD卡初始化软件流程图
图5 SD卡读扇区结构图
图6 SD卡写扇区结构图
STM32F103R内含RTC设备,利用这个设备可以轻松地实现实时时钟功能,从而为文件系统提供准确的时间。相关的软件工作就是RTC的设置以及日历系统的实现。
完成了上面的基础工作后,就可以开始进行FatFs的移植,具体的移植工作有2步:编写FatFs接El函数和FatFs的设置。
(1)FatFs的接口函数
这项工作就是编写disk.C中的6个函数。
DSTATUS disk_initialize(BYTE Drive):存储介质初始化函数。本设计中就是SD卡的初始化函数。Drive是存储介质号码,本设计只需支持SD卡一个存储介质,因此Drive设为0即可。
DSTATUS disk_status(BYTE Drive):存储介质状态检测函数。检测是否支持当前的存储介质。事实上只要Drive为0,系统就默认为支持,函数执行无误返回0。
DRESUT disk_read(BYTE Drvive,BYTE*Buf,DWORD SectorNumber,BYTE Sector Count):读扇区函数。在SD卡SPI接口函数的基础上编写,Drive设为0,*Buf指向存储的数据,SectorNumber是读的起始扇区,SectorCount是需要读的扇区数目。函数执行无误返回0,错误返回非0。
DRESULJTdisk_write(BYTE Drvive,BYTE*Buff,DWORD SectorNumber,BYTE Sector Count):写扇区函数。在SD卡SPI接口函数的基础上编写,Drive设为0,*Buf指向写入的数据,SectorNumber是写的起始扇区,SectorCount是需要写的扇区数目。函数执行无误返回0,错误返回非0。
DRESULT disk_ioctl(BYTE Drive,BYTECommand,Void*Buf):存储介质控制函数。Command是控制命令,Buf指向存储或接收的控制数据(命令参数)。可以在此函数里编写自己需要的功能代码,比如获取存储介质的容量、检测存储介质的相关信息等。如果是简单的应用,也可以不编写,函数直接返回0即可。
DWORD get_fattime(Void):实时时钟函数。需要RTC函数的支持。返回一个32位无符号整数,时钟信息包含在这32位中,如图7所示。
图7 时钟位
(2)FatFs的配置
通过FatFs的配置,可以根据需要对代码进行裁剪,以获取最适合的代码,该工作主要是在fconf.h中完成的。FatFs的配置可以分为4类,如图8所示。
图8 FatFs配置结构图
Function and Buffer:对FatFs进行功能性的裁剪,有6个选项。
#define_FS_TINY(0或者1)。设置为1的时候,FatFs在进行数据传输时使用文件系统自建的缓存,这样可以减少内存的占用率。
#define_FS_READONLY(0或者1)。设置为1的时候文件为只读,编译时移除与写入相关的函数。其余的4个选项都是对代码进行裁剪的。
Locale and Namespace:对文件所支持的语言,有5个选项。
#define_CODE_PAGE。有多个取值,取不同的值可以支持不同的语言。例如,取936就支持简体中文,取437就支持美式英语。这里取1,支持ASCII,此时不需要对此类中其余的选项进行配置。
Physical Drive:与实际物理磁盘相关的配置,有3个选项。
#define_DRIVES。物理磁盘的数量,设为1。
#define_MAX_SS。扇区大小,在使用Memory Card时必须设为512。
#define_MULTI_PARTITION。分区数量,设为0。
System:文件系统的配置,有3个选项。
#define_WORD_ACCESS。字写入方法的配置,推荐设置为1以获得较好的性能。
但是当处理器使用大端模式或设为1时,系统运行不正确时,应设为0。
#define_FS_REENTRANT。Reentrancy的使能,设为0时剩下的两个函数(_FS_TIMEOUT,_SYSNC_t)失效。这里设为0。
在测试中STM32F103R采用12MHz的晶振,设置SPI时钟为6MHz,分别对2GB的micro SD(Kingston)和4GB的SDHC(Transcend)的卡进行读写。通过对一定容量(200KB和10MB)的文件读写时间来计算读写速度,测试结果如表1所示。
从测试结果上可以看出,读写速度令人满意,若采用更快的SPI时钟,读写速度可以进一步提高,完全可以适应嵌入式系统的需求。
本文总结了基于FatFs文件系统的SD卡存储器设计方案,该存储器读写速度快,可靠性强,设计流程简单,为嵌入式数据的存储提供了一种较好的方法。