FATFS搭建以及测试方案.docx
《FATFS搭建以及测试方案.docx》由会员分享,可在线阅读,更多相关《FATFS搭建以及测试方案.docx(13页珍藏版)》请在冰豆网上搜索。
FATFS搭建以及测试方案
第一部分FATFS系统的特点和原理
FatFs是一个为小型嵌入式系统设计的通用FAT(FileAllocationTable)文件系统模块。
FatFs的编写遵循ANSIC,并且完全与磁盘I/O层分开。
因此,它独立于硬件构架。
它可以被嵌入到低成本的微控制器中,如AVR、8051、PIC、ARM、Z80、68K等等,而不需要做任何修改。
图1.1FATFS示意图
其特点是:
◆兼容Windows的FAT文件系统
◆不依赖于硬件平台与架构,易于移植
◆代码和工作区占用空间非常小
◆多种配置选项
●多卷(物理驱动器和分区)
●多ANSI/OEM或Unicode中长文件名的支持
●RTOS的支持
●多扇区大小的支持
●只读,最少API,I/O缓冲区等等
另外,FatFs提供了丰富的API函数,包括驱动器的建立,文件的读写以及目录的设立等等。
第二部分FATFS文件系统移植主要实现功能分析
2.1功能分析
结合项目实际情况,本次FatFs文件系统的移植主要实现的功能为:
◆通过特定的“开始”按键等输入控制文件的创建以及实验的开始;
◆从节点收集的数据持续写入特定的txt文件中,在写入过程中需要加入断电保护使得设备在突发断电中可以将当前缓存中的数据全部写入或者舍弃;
◆按下“结束”按键,停止本次实验,并生成第一次实验数据文件,再度按下“开始”按钮开始实验时会重新建立一个新的txt文本文档,并将数据写入;
◆在实验过程中需要对当前SD卡的读写状态进行监视,比如写入的状态和剩余的容量等:
Ø当SD卡剩余容量小于一定界限时(此界限可根据反应时间和写入速度决定),会给予报警信号进行提示;
另外,分析以下功能实现的主要矛盾点:
◆传感器节点采样速度为200Hz,平均5ms一次,每次采集数据大小约为1KB,所以SD卡写入速度理论上应为200KB/s。
这个速度会受到写入次数、文件系统操作次数以及文件数量的影响。
◆写入的数据需要断电保护,主要目的是防止断电使得一帧数据并未完全写入txt文件中,成为无用数据。
2.2主要实现函数与流程
根据以上需求,在本次SD卡文件系统的实现中,主要使用f_mount、f_open、f_write、f_lseek、f_sync等函数,下面着重结合FATFS系统的原理对以上函数的工作流程进行分析。
根据FATFS的例程显示,一般的写操作包括以下几个步骤:
1.f_mount
主要功能:
注册/注销一个工作区。
描述:
f_mount函数在FatFs模块上注册/注销一个工作区。
在使用任何其他文件函数之前,必须使用该函数为每个卷注册一个工作区。
要注销一个工作区,只要指定FileSystemObject为NULL即可,然后该工作区可以被丢弃。
该函数只初始化给定的工作区,以及将该工作区的地址注册到内部表中,不访问磁盘I/O层。
卷装入过程是在f_mount函数后或存储介质改变后的第一次文件访问时完成的。
此函数主要功能是注册一个驱动器,以为后面创建文件所用。
2.f_open
主要功能:
创建/打开一个用于访问文件的文件对象。
描述:
如果函数成功,则创建一个文件对象。
该文件对象被后续的读/写函数用来访问文件。
如果想要关闭一个打开的文件对象,则使用f_close函数。
如果不关闭修改后的文件,那么文件可能会崩溃。
在使用任何文件函数之前,必须使用f_mount函数为驱动器注册一个工作区。
只有这样,其他文件函数才能正常工作。
另外,此函数创建的文件可设置多种模式,本例中由于需要创建并写入文档,则需要设置可写并自动创建的方式。
3.f_write
主要功能:
写入数据到一个文件。
图2.1f_write的工作原理示意图
描述:
先前的f_open是将一个创建的文件设置为活动的状态,也就是允许按照其事先设置的模式进行读写操作等。
文件对象中的读/写指针以已写入字节数增加。
该函数成功后,应该检查*ByteWritten来检测磁盘是否已满。
在写操作过程中,一旦*ByteWritten<*ByteToWritten,则意味着该卷已满。
4.f_lseek
主要功能:
移动一个打开的文件对象的文件读/写指针。
也可以被用来扩展文件大小(簇预分配)。
描述:
采集的数据是按照一定的频率写入文档的,每次写入需要在上一次写入的位置接着写,而非替换原有数据。
f_write的指针每次都默认指向文档开头。
因此,必须在写操作前将写指针移向文本最后。
5.f_close
主要功能:
关闭一个活动的文件。
描述:
f_close函数关闭一个打开的文件对象。
无论向文件写入任何数据,文件的缓存信息都将被写回到磁盘。
该函数成功后,文件对象不再有效,并且可以被丢弃。
如果文件对象是在只读模式下打开的,不需要使用该函数,也能被丢弃。
6.f_sync
主要功能:
冲洗一个写文件的缓存信息。
图2.2f_write的工作原理示意图
描述:
其执行过程与f_close相同。
但是文件仍处于打开状态,并且可以继续对文件执行读/写/移动指针操作。
这适用于以写模式长时间打开文件,比如数据记录器。
定期的或f_write后立即执行f_sync可以将由于突然断电或移去磁盘而导致数据丢失的风险最小化。
在f_close前立即执行f_sync没有作用,因为在f_close中执行了f_sync。
换句话说,这两个函数的差异就是文件对象是不是无效的。
本例设计的程序基本结构如下所示:
图2.3写数据流程图
第三部分FATFS移植测试问题分析与解决方案
3.1数据写入的测试
首先通过中断模拟汇聚节点收集数据的大小和速度,汇聚节点采样速率为200Hz,即每5ms采集一次,每次数据大小最大为1024字节。
首先需要STM32每5ms产生一个1024字节的数据包。
3.1.1测试1:
测试f_write的写入速度
测试目的:
当前工程使用的为SDIO的1线模式,其理论速度为2MB/s,理论上满足数据的写入速度,设计实验验证实际的数据写入是否满足200Hz的要求。
测试手段:
在写文件程序中,包括文件写指针的寻址以及数据的写入,每完成一个函数会控制一个LED灯的亮灭,通过示波器观察其电平拉低的时间,即为每个函数所需要的耗时。
测试代码:
1for(write_count=0;write_count<4000;write_count++)
2{
3GPIO_Write(GPIOC,0xfe);
4res=f_lseek(&fil,fil.fsize);
5GPIO_Write(GPIOC,0xff);
6GPIO_Write(GPIOC,0xfd);
7res=f_write(&fil,testBuffer,sizeof(testBuffer)-1,&br);
8res=f_sync(&fil);
9GPIO_Write(GPIOC,0xff);
10}
11f_close(&fil);
观察现象:
通过示波器可以观察到f_lseek耗时约为40us,f_write与f_sync的耗时共约为5ms,其速度不仅不符合工程要求,甚至也不符合其理论速度。
经过验证,f_write与f_sync耗时相当,均约为2.7ms,仅计算f_write的写入速度。
另外,在写入循环中,任意时间拔掉SD卡,在PC中对文本进行观察,可以发现在f_write后加入f_sync,并不会存在一个testBuffer仅有一部分被写入的状况,循环所写入的数据均保存在文档中可以显示,不存在乱码。
可以看出,原本设置为4000次的有限循环,在中间任意时刻拔出后,可以观察到其中47次有效写入,如图3.1(a)所示。
(a)(b)
图3.1SD卡文件写入状况
但是如果将f_write之后的f_sync注释掉,在循环中任意时间拔掉SD卡,在PC中对文本进行观察,则可以发现文本中并没有已经完成的写操作的数据,为空文本,也不存在乱码现象,文本占用空间为0,但是,查询SD卡的属性可以发现有空间被占用,如图3.1(b)所示。
解决办法:
从以上分析可知,如果需要加入f_sync断电保护的这个函数,则一次写操作需要5.5ms,但是其速度远远达不到要求。
因此,拟采用SDIO的4线模式对SD卡进行读写操作来大大提高其读写速度。
3.1.2测试2:
FATFS工程SDIO的4线模式修改
整个SD卡的初始化过程基本分为三大步:
可以参见main.c中的C124的SD_USER_Init:
第一步:
SDIO外设的初始化以及SD卡本身的上电。
第二步:
获取SD卡的信息。
第三步:
设置SD卡的总线宽度。
第四部:
设置DMA的工作模式。
使用官方库的SDIO和sdcard进行移植和设置4线模式之后,SD卡并不能有效的初始化,errorstatus会返回SD_START_BIT_ERR的错误信息,但是,很明显SDIO是支持4线模式的。
因此需要对官方库进行修改。
从目前调试的结果来看,主要问题出现在SD卡上电初始化存在问题,另外则是时钟频率设置的问题。
接下来将针对SDIO的4线模式对官方固件库进行修改。
Ø第一个问题首先出现在SD卡的上电初始化过程中。
描述:
本工程中将所有的初始化过程都放在了disk_initialize(0)(main.c->C68)这个函数中,此函数的主要功能为初始化SD硬件。
其中的功能包括对SD卡基本功能的设置函数:
SD_USER_Init()(main.c->C124)(由于此函数需要用户自定义,所以放在了main.c中进行了定义)以及初始化信息的返回。
SD_USER_Init函数第一步便是对SD卡的初始化:
SD_Init(main.c->C129)此函数的详解可见于其定义处(sdcard.c–>C129)。
其中包括对GPIO,SDIO以及DMA时钟的配置,以及对SDIO外设寄存器的默认设置(SDIO_Deinit->C142)。
完成以上设置,接下来进入:
SD_PowerON(sdcard.c->C181)也就是SD卡的上电步骤。
在这个步骤中首先要注意此函数仅是为了配置SD卡,因此仅需要一根线,而且时钟频率也只需设置为400kHz,所以并不需要在此步设置4线模式。
在SD_PowerON中存在一处修改,从SD卡协议中(Page91)可以发现在上电后有需要等待74个时钟之后电压到达有效值之后才可以接着发送CMD0,但是在官方库的代码中并未等待这74个时钟。
因此在sdcard.c的C204-216添加了74个循环。
图3.1上电流程图
SD_InitializeCards函数主要发送CMD2和CMD3,获得CID寄存器内容和SD卡的相对地址(RCA),并通过CMD9,获取CSD寄存器内容。
到这里,实际上SD卡的初始化就已经完成了。
SD_Init函数又通过调用SD_GetCardInfo函数,获取SD卡相关信息,之后调用SD_SelectDeselect函数,选择要操作的卡(CMD7+RCA),通过SD_EnableWideBusOperation函数设置SDIO的数据位宽为4位(但MMC卡只能支持1位模式)。
经过此修改,初始化通过,并且获取卡的类型。
上电部分的其它函数则参照以下流程图:
Ø第二个问题出现在CMD55没有足够的处理时间以导致程序会进入一个死循环。
由于修改时钟频率带来的错误。
最开始配置SDIO时,其频率并不能设置为25MHz,而是应为400kHz,1线模式。
初始化完成之后才应将时钟频率提高至25MHz。
另外,时钟速度最高为25MHz,高于此速度会导致SDIO传输不可用。
SD_EnableWideBusOperation(sdcard.cC655)则是设置SDIO读写时钟频率以及4线模式的函数。
在C672-688中间是对SDIO传输模式的设置。
但是在官方的驱动中,程序会卡在SDEnWideBus(sdcard.cC674)中的FindSCR(sdcard.cC2440)中的C2764处,无法继续进行。
此错误主要是因为在此函数的C2744处没有给予足够的时间处理命令,需要加一段时间的延时(C2746-2747)。
另外添加了C2770-2771两行代码以保证最后可以跳出该循环。
Ø第三个问题出现在SDIO的时钟速率上。
初始化的最后会设置SDIO_CK时钟的频率,并设置工作模式(DMA/轮询)。
在DMA模式中,如果只读,可以设置SDIO_CK的时钟为24Mhz,而如果要读写的话,这个时钟设置为18M左右比较合适,否则出错的几率比较大,虽然我们的代码加入了防出错处理,不过这样会降低写入效率。
而轮询模式,则必须设置SDIO_CK时钟频率不大于18Mhz,否则不能正常读写。
以上问题解决后,SDIO可以用4线模式传输数据(D0~D3均有数据传输),而且较为稳定,但是速度仍然受限为500kB/s。
并且无论将时钟分频为24,18或14MHz,在写入任务(循环4000次写入,每次1KB,共计4MB)相同的情况下,使用手机的表秒功能进行计时,最终其写入速度均为500kB/s左右。
表3.1FATFS文件系统下SDIO传输速度测试结果
SDIO_CK的输出频率
写入数据总大小
单次试验用时
平均写入速度
24MHz
4MB
8.32s
480KB/s
18MHz
4MB
8.59s
465KB/s
14MHz
4MB
8.11s
493KB/s
可以发现,写入任务所需时间并不随时钟的变化而变化,上述的单次试验用时的微小偏差可以认为是人为原因导致的,可以忽略不计。
分析:
虽然SDIO的理论写入速度为12MB/s,但是SD本身的写入速度也会受到其等级和品质的影响。
所以需要进一步对SD卡本身的读写能力进行测试,以确定其速度受限的根本原因。
3.1.3测试3:
不带文件系统的SD卡读写测试
方案设计:
为了测试其写入速度受限的来源是否为FATFS文件系统,拟直接通过SDIO口将数据传输至SD卡中。
为将变量尽可能减少,仍然与测试3采用相同的写入任务,即单次1KB,分为4000次写入,并分为多种时钟(24,18,14MHz)观察平均写入速度。
测试手段:
将原有的SD卡测试例程移植到现有的SDIO_4bits的,并直接写入数据。
写入任务与带有文件系统的SDIO读写测试相同。
可以发现其速度有略微的提升,但是仍远未达到额定速度。
表3.2无文件系统的SDIO传输速度
SDIO_CK的输出频率
写入数据总大小
单次试验用时
平均写入速度
24MHz
4MB
7.02s
569KB/s
18MHz
4MB
6.57s
608KB/s
14MHz
4MB
6.32s
632KB/s
鉴于此,需要另外考虑修改方法。
3.1.4测试4:
FATFS读写原理以及改进
调试源码可以将其写数据的过程总结为下图的流程,总体来说的原理为每满512字节往SD卡里写一次数:
以此为基准,如果每次写入2048B的数据,进一步测试其写入的平均速度为:
假设每次用f_write向文件内写入700字节,因为FATFS的机制,他会把512字节直接通过disk_write直接写入SD的物理磁盘,另外188字节存到数据缓冲区中等待至下一次700字节写的324字节凑够512字节写入。
因此,在RAM中开一段循环Buffer,新采集的不定长数据会循环写入Buffer中,而数据读取也会按照固定的长度循环进行,以此提高数据发送的速度。