标签:bytes 填充 超过 hello 关心 move out 分区 text
Zynq Fatfs文件系统应用笔
Hello,panda
笔记介绍基于所描写叙述的Zynq Fatfs基于Xilinx xilffsv3.0和Sdpsv2.4,文件系统採用在Bare-Metal和轻量级操作系统中经常使用的FatFs,版本号为v0.10b。
在開始介绍FatFs文件系统在Zynq实现之前一定要先对FAT32文件系统有一个清晰的了解。
应用笔记针对SD上的FAT32文件系统,在对文件系统作具体介绍之前,先回想一下硬盘的结构,如图1:
图1 硬盘结构
对一个机械硬盘而言。柱面、磁头、扇区确定唯一的扇区物理地址。在数据组织上来看,总是依照主引导区→引导扇区→数据→引导扇区…来排列,一块硬盘上,基本分区的最大数目为4个。大于4个的被自己主动分配为扩展分区。
SD卡的分区结构和普通磁盘类似,沿用了普通机械硬盘的大多数概念术语。
由于它无需启动,所以MBR区没有引导信息,图2是SD卡文件系统的典型结构。
图2 SD卡文件系统结构
在一个硬盘中主引导分区位于硬盘的起始扇区,一共512个字节,包括了446字节的MBR和64字节的DPT,并以55 AA作为结束标志。
由于SD卡不用启动,因此MBR区域不包括引导数据,SD卡的MBR如图2所看到的,数据均为小端模式,低字节在前。
图2 SD卡MBR区域
图2所看到的为SD卡物理地址为0開始的512字节区域,红蓝线标注的数据包括了两个重要信息:
① 红线数据:表示下一个分区的扇区地址,这里是0x2000。即下一个分区从第8192个扇区開始。也就是DBR在第8192个物理分区(0逻辑分区)。
② 蓝线数据:表示总扇区数为0x01DAAC00,那么能够计算得到当前SD卡的总容量为:
ρ=0x01DAAC00*512= 14.83GB
引导扇区DBR共512个字节。以55 AA结束,前11个字节为跳转指令和文件系统类型、版本信息。结构如图3所看到的。
图3 DBR内容
DBR为逻辑分区起始位置,须要关注下面重要信息:
① 偏移地址0x0D标记每簇的扇区数,图3显示为64,即每簇为32KB,文件系统中保存数据的最小单位为簇,仅仅要本簇中写入了当前文件的数据。它就不能够被其它文件使用。
② 偏移地址0xE~0xF标记了本分区的保留扇区数,图3中为598个,也就是说下一个分区(FAT表)的起始扇区为逻辑扇区598。
③ 偏移地址0x10~0x11标记了FAT表的个数,图3显示为2个。
④ 偏移地址0x24~0x27标记了FAT表的大小。图3显示为3797个。
信息分区FSINFO的结构很easy,用以记录文件系统中空暇簇的数量以及下一可用簇的簇号等信息,以供操作系统作为參考,常位于1号逻辑扇区。
如图4所看到的。
图4 FSINFO内容
图4中红色方框的为FSINFO签名。固定为0x61417272;蓝色方框中内容为文件系统的空簇数,依据使用情况动态变化;黑色方框为下一个空簇的位置,依据使用情况动态变化。
通常情况下,2号扇区也以55 AA结束,6号扇区是DBR的备份,7号扇区是FSINFO的备份。8号扇区是2号扇区的备份。
从FAT表開始便是文件系统的核心内容。文件占用磁盘的最小单位是簇。即使文件仅仅有一个字节。那么它也占用一个簇的磁盘空间,大文件会占用多个簇。同一个文件的数据并非连续的存放在一段磁盘空间内,而是分成若干段,像链子一样存放。称之为文件的链式存储。为了实现文
件的链式存储。文件系统必须准确地记录哪些簇已经被文件占用,还必须为每一个已经占用的簇指明存储后继的下一个簇的簇号,对于文件的最后一簇。则要指明本簇无后继簇。这些都是由 FAT 表来保存的,FAT 表相应表项中记录着它所代表的簇的有关信息:诸如是空,是不是坏簇,是否是已经是某个文件的尾簇等。
对于FAT表而言。它的重要使命是:描写叙述簇的分配状态以及标明文件或文件夹的下一簇的簇号。
FAT表中每簇的地址固定为32bit。按四字节对其进行划分。并由0開始进行编号。
0号和1号簇由系统保留作特殊使用,从2号簇開始相应文件系统的实际数据区的簇号,FAT表中的簇地址编号与数据区的簇号同样。
在创建文件系统(格式化)时。全部的FAT表均被清空,FAT1和FAT2的0、1号表项写入特定值,2号表项常为根文件夹,因此2号表被写入结束标志。
① FAT32文件系统FAT表的0号表项固定为0x0FFFFFF8;
② 1号表项正常情况为0xFFFFFFFF或0x0FFFFFFF。也可能被用于记录脏标志,以说明文件系统没有被正常卸载或者磁盘表面存在错误。
③ 若簇未被分配使用,则其FAT表项为0;
④ 若该簇被使用,那么FAT表项值就是该文件下一个存储位置的簇号,如是文件结束簇,则写结束标志“0x0FFFFFFF”;
⑤ 若该簇存在坏扇区。则用“0xF7FFFFF”标记该簇为坏簇;
⑥ 新建文件夹时。仅仅为其分配一个簇的空间,相应的FAT表现写入结束标志,当文件夹超过一个簇时则在空暇区再为其追加一个簇并又一次建立FAT表链。
图5是一个SD的FAT32文件系统FAT表,每四个字节一组表示一个簇的信息。簇号从0開始。
① 0x0FFFFFF8: FAT表起始标志;
② 0xFFFFFFFF:不用,默认值;
③ 0x0FFFFFFF:根文件夹所在簇;
④ 从FAT表项第3项開始记录存储文件的信息。FAT表第三项记录了存储文件的下一个簇号为4,…直到第七项结束。
图5 FAT32文件系统FAT表实例
根文件夹所在的簇为3号簇,这个偏移地址能够通过计算得出。
① 逻辑地址:保留区大小+FAT表大小*2。那么本文中描写叙述的文件系统根文件夹的位置为 598+3797*2 =8192。
即根文件夹从逻辑扇区第8192扇区開始。
② 物理地址:隐藏区域+逻辑地址。本例中隐藏区域在MBR表中能够看到是8192。那么根文件夹的物理地址就是从第16384个扇区開始。
本例中每32KB为一个簇,2号簇即存储根文件夹的实际数据区域。
根文件夹在文件系统建立时即已被创建。其目的就是存储文件夹(也称文件夹)或文件的文件夹项。每一个文件夹项的大小为32个字节。这32个字节能够是长文件名称文件夹项、文件文件夹项、子文件夹项等。图6是本例中根文件夹的内容。
图6 根文件夹内容
首先重点提醒图6中显示‘X’号的文件是已经删除但没有格式化的文件数据,仍然能够恢复读出,所以“关键数据”删除后一定要记得深度格式化。
文件夹所在的扇区,都是以 32 Bytes 划分为一个单位,每一个单位称为一个文件夹项(DirectoryEntry ),即每一个文件夹项的长度都是 32 Bytes 。根文件夹由若干个文件夹项组成,一个文件夹项占用 32 个字节,能够是长文件名称文件夹项、文件文件夹项、子文件夹项等。
32 字节的详细定义例如以下表1所看到的。
表1 FAT32短文件名称文件夹项定义
字节偏移(16进制) |
字节数 |
定义 |
|
0x0~0x7 |
8 |
文件名称 |
|
0x8~0xA |
3 |
扩展名 |
|
0xB* (不可取值0F,0F表示长文件名称文件夹段) |
1 |
属性字节 |
00000000读写 |
00000001仅仅读 |
|||
00000010 隐藏 |
|||
00000100 系统 |
|||
00001000 卷标 |
|||
00010000 子文件夹 |
|||
00100000 归档 |
|||
0xC |
1 |
系统保留 |
|
0xD |
1 |
创建时间的10ms位 |
|
0xE~0xF |
2 |
文件创建时间 |
|
0x10~0x11 0x12~0x13 0x14~0x15 0x16~0x17 0x18~0x19 0x1A~0x1B 0x1C~0x1F |
2 2 2 2 2 2 4 |
文件创建日期 文件最后訪问日期 文件起始簇号的高16位 文件近期改动时间 文件近期改动日期 文件起始簇号的低16位 文件的长度(字节),单文件最大4GB |
以下分析图6中第一个32字节的内容,分析结果写入表2。
表2 根文件夹第一个32字节内容
字节偏移(16进制) |
字节内容 |
含义 |
0x0~0x7 |
47,49,52,47,52,41,57,20 |
文件名称”girlraw”的ASIC码 |
0x8~0xA |
52,41,57 |
扩展名raw |
0xB |
20 |
归档 |
0xC |
1 |
系统保留 |
0xD |
AE |
|
0xE~0xF |
8C56 |
Bit[15:11]:小时,17时 Bit[10:5]:分18分 Bit[4:0]:秒,2秒为单位,44秒 |
0x10~0x11 |
4703 |
Bit[15:9]:年,1980相对值,2015 Bit[8:5]:月。8月 Bit[4:0]:日。3日 |
0x12~0x13 |
470A |
|
0x14~0x15 |
0000 |
文件起始簇号的高16位 |
0x16~0x17 |
729D |
|
0x18~0x19 |
46F7 |
|
0x1A~0x1B |
0003 |
文件起始簇号的低16位,文件存储第一个簇的位置是3号簇 |
0x1C~0x1F |
00028000 |
163840个字节 |
FAT32 文件系统在为文件分配短文件名称文件夹项的同一时候会为其分配长文件名称文件夹项。文件系统在为文件创建长文件名称(Long File Name,LFN)类型的文件夹项时,并没有舍弃原有的短文件名称文件夹项。具有LFN的文件同一时候也有一个常规的SFN(Short File Name,短文件名称)类型文件夹项。
之所以仍然须要SFN。是由于LFN文件夹项仅仅包括文件的名字,而不包括不论什么有关时间、大小及起始簇号等信息,这些信息仍然须要用SFN文件夹项来记录。
假设一个文件的文件名称超过了 8 个字符,则会为其名字截短后为其建立短文件名称。将短文件名称存储在短文件名称文件夹项中,长文件名称则存放在长文件名称文件夹项中。
长文件名称文件夹项具有下面特点:
① LFN 和 SFN 文件夹项结构在同样位置有一个属性标志字节,LFN 文件夹项使用一个特定的属性值,以说明它是一个长文件名称项。
② 项中的其它字节。使用UTF-16 编码,存储 13 个 Unicode字符的文件名称,每一个字符占用两个字节;
③ 假设文件名称长于 13 个字符,则继续为其分配LFN 项,直到够用为止;
④ 全部 LFN 都包括一个校验和,通过这个校验和将其与对应的SFN 项关联起来;
⑤ 一个文件的全部 LFN 项按倒序排列在它的 SFN项前面。即文件名称的第一部分距离 SFN 是近期的。
表3是长文件名称文件夹项的详细结构。
表3 长文件文件夹项定义
偏移字节 |
字节数 |
含义 |
0x00 |
1 |
如文件夹项使用中则为序列号。未分配则为0x00。以前使用但已经被删除则为0xE5。一个文件的第一个长文件名称文件夹项的序号为0x01,然后依次递增,若是最后一项则将该文件夹项序号与0x40进行OR运算后写入。 |
0x01~0x0A |
10 |
文件名称的1~5字符(Unicode),未使用部分先填充两个0x00,然后用0xFF填充 |
0xB |
1 |
长文件名称文件夹项属性标志0x0F |
0xC |
1 |
保留未使用 |
0xD |
1 |
校验和,如一个长文件名称须要几个长文件名称文件夹项进行存储,则他们具有同样的校验和 |
0x0E~0x19 |
12 |
文件名称的6~11个字符,未使用部分先填充两个0x00,然后用0xFF填充 |
0x1A~0x1B |
1 |
保留未使用 |
0x1C~0x1F |
4 |
文件名称的12~13个字符,未使用部分先填充两个0x00,然后用0xFF填充 |
图7是根文件夹下长文件名称文件夹项的截图。
图7 长文件名称文件夹项
如图7所看到的,红色方框部分文件名称占用三个文件夹项,最以下的是短文件名称文件夹项,指定了文件的全部属性;紧挨短文件名称文件夹项倒着向上数是第一第二条长文件名称文件夹项。
① 第一条长文件名称文件夹项的序列号直接为0x01,这和短文件名称文件夹项第七个字节的跳转指示序号同样;第二条长文件名称文件夹项未终止项,值为0x02 or 0x40 = 0x42。
② 第一和第二条长文件名称文件夹项具有同样校验和0x69。
在FAT32文件系统中。除根文件夹在创建文件系统时即被建立并分配空间外,其它全部的子文件夹都是在使用过程中按需建立。新建一个子文件夹时,在其父文件夹中建立文件夹项。在空暇空间中为其分配一个簇并对该簇进行清零操作。同一时候将这个簇号记录在它的文件夹项中。假设在根文件夹下创建一个子文件夹,那么这个子文件夹就是根文件夹的子文件夹,称根文件夹为这个子文件夹的父文件夹。
创建子文件夹时,在其父文件夹所在簇为子文件夹建立文件夹项,记录了子文件夹的起始簇号。同一时候,在为子文件夹分配文件夹项的簇中。用前两个文件夹项描写叙述它与父文件夹的关系。
图8 子文件夹项前两个文件夹的内容
从图8子文件夹项的前两个文件夹能够看到,文件系统创建了.和..两个文件夹。当中.文件夹项描写叙述了该子文件夹自身的信息;..文件夹项描写叙述了其父文件夹的信息(创建该文件夹所在文件夹的第一个簇号,根文件夹为0x00),建立了子文件夹和父文件夹之间的联系。
从第三条文件夹项開始为下级子文件夹或文件建立的文件夹项。
① “.”文件夹项,该文件夹指向自身,图8中它的簇号为0x03,就是当前所在簇。
② “..”文件夹项指向它的父文件夹所在簇,图8中它的父文件夹簇号为0x00,那么指示创建该文件夹的文件夹为根文件夹。
本节简要介绍建立、读取和删除文件的步骤。
目标:在根文件夹下建立一个叫QspiFlash的子文件夹。并向子文件夹中写入名为“Zynq Qspi 控制器应用笔记.docx”的文件。
簇大小格式化为32KB,待写入的文件大小为33KB,需占用两个簇。
第一步:读取引导扇区DBR,依据引导扇区的信息来定位FAT表、根文件夹和数据区的位置;
第二步:查看根文件夹下的每一个文件夹项。找到名字为“QspiFlash”且具有子文件夹属性的文件夹项。找到它的起始簇号为0x03;
第三步:读取3号簇的内容,查找每个文件夹项。直到找到未分配的位置。
第四步:找到后写入文件名称“ZynqQspi 控制器应用笔记.docx”及其相关属性;
第五步:为文件数据分配空间。转到FAT表。寻找FAT表中未使用的空间。发现4号簇未使用,将4号簇中写入结束标记;
第六步:将数据写到4号簇中并将簇号写到文件文件夹项中。为剩下1KB数据寻找下一个可用簇;
第七步:在FAT表中寻找可用簇。发现5号簇可用,那么将4号FAT表项值该为5并在5号FAT表项值中写入结束标记;
读取文件的过程和建立文件的过程相反。
第一步:和建立文件第一步第二步同样;
第二步:在3号簇中查找每个文件夹项,找到名为“Zynq Qspi 控制器应用笔记.docx”的文件并获取其相关属性。
第四步:读取第一个簇的数据并转到FAT表。将下一个簇的数据读出,直到所有读出。
删除文件实质就是:
① 将簇所在FAT清零;
② 将文件文件夹项的第一个字节清零;
删除文件仅删除FAT表和置文件夹项标记,实际文件数据并未及时删除,能够依据文件系统的构成特点所有恢复或部分恢复。
SD卡系列规范由Panasonic、SanDisk、Toshiba等发起。处理器端的SDHost、SD卡(SD Device)和文件系统都必须遵循下列规范:
《SD Specifications Part1 Physical Layer Specification》
《SD Specifications PartA2 SD Host Controller Standard Specification》
《SD Specifications Part2 File System Specification》
(1)容量:SD标准协会定义,容量≤2GB的为标准卡。超过2GB的为大容量卡。
(2)电压:高电压供2.7~3.6V;双电压供电LowVoltage Range 和2.7~3.6V双电压;
(3)速度:默认模式0~25MHz时钟频率,快速模式0~50MHz时钟频率。
SD卡均能通过4bit/1bitSD模式或模式訪问,这里仅仅对SD模式作简要说明。
上电SD默觉得1bit SD模式。Host可通过命令动态重配。命令和应答通过CMD线传输,数据通过DATA线传输。
命令訪问格式如图9所看到的。
图9 SD卡命令訪问及应答格式
SD总线数据訪问有两种格式,各自是常规数据訪问和宽位宽数据訪问。
图10 常规数据訪问
常规数据訪问如图10所看到的,总是以MSB的格式输出,在4bit模式下,CRC每通道单独校验。但校验状态仅仅通过DATA0输出,CRC校验位为16bit。宽位宽数据訪问如图11所看到的,也是MSB的格式输出,但它的位宽单位固定是512bit。
图11 宽位宽数据訪问
SD卡擦除写入数据的最小单位为Block。一个Block的大小固定为512B。对于标准卡。擦除起始地址和擦除结束地址命令后跟的地址单位都是字节。因此须要文件系统保证512B对齐;对于高容量卡,擦除起始地址和擦除结束地址命令后跟的地址单位都是Block。
SD卡初始化包含SD复位、工作參数握手等工作,初始化流程如图12所看到的。
图12 SD卡初始化流程
有关SD物理层更加具体的操作以及具体的命令含义请查找SD协会颁布的标准文档:《SD Specifications Part 1 Physical Layer Specification》。
SD初始化完毕后。对它的读写操作实际上訪问其扇区数据。通过发送CMD25实现写数据、CMD18命令实现读数据;至于读写数据到哪个位置(扇区),数据的内容是什么。SD卡物理层并不关心。都是通过文件系统进行管理。
Zynq SD控制器符合《SDSpecifications Part A2:SD Host Controller Standard Specification》的定义,有SDMA(单操作DMA)、ADMA1(有4K边界限制)和ADMA2(在32位系统中同意不论什么位置和随意大小)。
接口兼容eMMC、MMC3.31、SDIO2.0、SD2.0、SPI。支持SDHC、SDHS器件。
以下描写叙述SD控制器的一些关键特点。
控制器採用读和写通道各自双缓冲FIFO的机制提高吞吐带宽。
SD控制器读写通道採用独立的512byte深度的双缓冲FIFO,在写操作时,处理器向第二个FIFO DMA数据时。可将第一个FIFO的数据写到SD总线;在读操作时,SD总线向第一个FIFO写数据时,处理器可将数据从第二个FIFO的数据读出。通过双缓冲机制以保证最大带宽。
在写传输中,仅仅有当当中一个FIFO中数据准备好且SD总线空暇时HOST才会向SD卡写数据。因此不会发生FIFOUnderrun的条件。在DMA模式下,仅仅有当FIFO能够接受一个Block的数据后才释放DMA读请求命令;在非DMA模式下,仅仅有buffer write ready中断产生后才可写数据到FIFO。
在读传输过程中。当FIFO都写满后HOST会停止SD时钟暂停传输,因此不会出现Overrun的情况,在DMA模式下接收到一个Block数据后才释放DMA写命令;在非DMA模式。接收到readready interrupt后处理器方将数据写到内存。
这样的模式既能够在DMA模式下使用,也能够在非DMA模式下使用,写操作时WRITE_DAT_UNTIL_STOP(CMD20)開始,直到STOP_TRANSMISSION结束;读操作时READ_DAT_UNTIL_STOP(CMD11)開始。直到STOP_TRANSMISSION结束。
在这样的模式下由于不知道数据的长度,所以在传输数据中建议将Block Size寄存器设置为最大的512Byte,这样子当读写512Byte数据后会切换FIFO。
本节描写叙述HOST到SD卡传输的编程模型。
SD卡传输协议包括三种模式:
(1) 单块传输:总块数HOST已知。但一次仅仅传输一个块;
(2) 多块传输:总块数HOST已知,一次传输一个或多个块;
(3) 无限制传输:总块数HOST未知。传输直到收到中断传输命令运行,传输中断命令在SD Card为CMD12。SDIO为CMD52。
下图13是无DMA传输的流程图。在无DMA传输过程中,处理器须要等待SD控制器中断或轮询状态,数据组织也全然须要通过处理器来完毕。占用CPU资源非常大。下面是对流程图步骤的分解:
(1)设置BlockSize寄存器,Block_Size_Block_Count.Transfer_Block_Size,对CMD17, CMD18, CMD24, CMD25, CMD53訪问有效,仅在未发生传输时能够改动。
(2)设置BlockCount寄存器,Block_Size_Block_Count.Blocks_Count_for_
Current_Transfer。
仅在多块传输模式下有效。控制器在每传输完一块后自减,仅仅有在空暇时能够改动。
(3)设置Argument寄存器,该寄存器需写入SD訪问CMD的bit[39:8];
(4)设置Muti/Single模式。BlockCount使能,Data传输方向,AutoCMD12等,配置Transfer_Mode_Command寄存器。
(5)写Command寄存器。当写寄存器的最高字节时,SD控制器发出命令。
(6)等待命令完毕中断。
(7)向中断状态寄存器位写‘1’清除中断位。
(8)读命令响应寄存器获取从SD卡得到的相关信息。
(9)推断是写操作还是读操作;
(11)等待bufferwrite ready中断,在无DMA写操作模式下,MCU冲当Master,在收到该中断后,通过BufferData Port register向FIFO中写数据,仅仅有当FIFO为空或者能够接一整帧的数据后释放该中断。
图13 是无DMA传输模式流程图
单DMA传输的流程图如图14所看到的,在这样的模式下,数据搬运通过SDMA完毕,无需处理器參与。释放了CPU资源。
在SDMA模式下,SystemAddress存储的是传输数据的实际地址。
图14 单DMA模式下操作流程图
使用ADMA传输和SDMA传输类似。仅仅是ADMA的性能更好。ADMA传输的流程图如图15所看到的。
使用ADMA传输时。ADMASystem Address寄存器里存储的是地址描写叙述表(descriptor table)的首地址,当Block Count Enable使能时。通过Block Size和Block Count寄存器确定数据传输的大小,但总大小需和descriptor table的描写叙述同样,因为Block Count寄存器仅仅有16bit,表示的范围有限。
当Block Count Enable关闭时。数据传输的大小仅仅由descriptor table决定。地址描写叙述表有32位地址模式和64位地址模式两种,在32位系统中採用32位地址模式。
图15 使用ADMA传输流程图
ADMA1有4K边界限制,ADMA2没有,在一般的系统中ADMA2使用更加灵活。两者的地址描写叙述表(descriptor table)也不同。
图16是ADMA descriptor table的结构。
图16 ADMA descriptortable结构
(1) ADMA1地址描写叙述表
使用ADMA1的起始地址必须是4K边界的顶部。但它能够降低descriptortable的尺寸,。
ADMA1 descriptortable每一条为32bit。图17是descriptor table的详细含义。其内容由Host驱动程序组织。请注意ADMA1 descriptor table存储也必须遵循4KB边界限制。
图17 ADMA1 descriptor table位定义
① Nop。表示无操作,ADMA直接跳过这一条。
② Set。表示获取数据长度,ADMA启动默觉得4KB,通过该命令改动。
③ Tran,表示获取首地址并启动传输,地址必须是4KB顶部。
④ Link。表示链接到下一个descriptor table的地址。
(2) ADMA2地址描写叙述表
使用ADMA2仅仅须要保证32位对其就可以,其descriptortable的地址既能够是32位也能够是64位,分别用于32位和64位的系统。
图18是ADMA2 descriptor table位定义。
图18 ADMA2descriptor table位定义
图18中所看到的Length域最大为65536字节(Length=0x0000),超过64KB即要利用Link命令新建新的descriptortable。直到能够将整个文件所有传输完成。假设文件传输完成须要使能中断,那么END位和Int位均要置1。
SD存储卡採用CMD12。SDIO採用CMD52命令,有两种情况下的终止传输:
(1) 终止无限制传输;
(2) 终止多重块传输。
终止方式也有同步终止和异步终止两种方式:
(1)同步终止:向BlockGap Control寄存器的Block Gap Request写‘1’停止当前传输。等待传输完毕后释放终止命令。最后再进行数据线和命令线的复位。
(2)异步模式:在CommandInhibit不为‘1’的不论什么时刻;
一般来说。仅仅有在事先并不知道传输文件长度的情况下才会选择中断传输操作。
Xilinx SDK提供非操作系统下的基于FatFsv0.10b的轻量级文件系统实现。SDK2015.2下的库版本号是xilffsv3.0。
FatFS文件系统是开源的轻量级文件系统,作者思路很清晰,代码短小精悍,有FatFS通用版和FatFs Tiny板两个版本号。
通用板适合在ARM、PowerPC等RAM较大的处理器上实现,Tiny版适合在C51、AVR等RAM较小的处理器上实现。FATFS具有下面突出特点:
(1) 结构清晰,代码量少,文件系统和IO底层分开,特别适合刚開始学习的人学习。
(2) 支持最多10个逻辑盘符和两级文件夹;
(3) 支持FAT12/FAT16和FAT32文件系统;
(4) 支持长文件名称。默认支持8字节的短文件名称。
从实现上说,FatFs文件系统仅仅负责文件系统的文件管理,对底层仅仅规定了调用接口函数规范。详细的驱动需依据不同平台差别设计。
FatFs文件系统最多能够挂在10个卷,图19是FatFs文件系统能够支持的设备层次结构图。
这样的,文件系统层与底层独立的结构能够让应用层訪问不同的地层设备。
眼下。FatFs主要是用于SD(MMC)文件系统,用于U盘、NAND Flash还比較少。
图19 FatFs 支持设备层次结构
能够通过FatFs官网获取最新版本号的函数接口技术文档或搜索keyword“FatFs通用FAT文件系统 0.09a中文手冊”获得国内技术人员翻译的中文文档,这里不再详述。
Zynq FatFs实现的结构如图20所看到的,实现是完毕diskio.c中的相关调用函数。
图20 FatFs实现结构
用户应用程序就是调用文件系统的相关数据进行创建文件夹、格式化、写入文件、读出文件等操作。下面是向SD卡写入文件的样例。
/***************************************************************************************
* SDWriteAccess()
* Description : This function provides theSD Card interface for the Simplified header
* functionality of Write.
* Argument(s) : SourceAddress is address inDDR data space;
* LengthBytes is the number of bytes to move;
* filename is the name of the Write file inSDcard
* Return(s) : XST_SUCCESS if the controller initializescorrectly
* XST_FAILURE if the controllerfails to initializes correctly.
* Caller(s) : any.
* Note(s) : none.
****************************************************************************************/
FILfil; /* File object */
u32SDWriteAccess(u32 SourceAddress,u32 LengthBytes,constchar *filename)
{
FRESULT rc; /* Result code*/
UINT bw;
strcpy_rom(buffer,filename);
file_name= (char*)buffer;
rc= f_open(&fil, file_name, FA_OPEN_ALWAYS | FA_WRITE);
if (rc) {
xil_printf("SD: Unable to Write File %s\n", file_name);
return XST_FAILURE;
}
rc= f_lseek(&fil, fil.fsize);
if (rc) {
xil_printf("Shift Pointer To the End of File Failed \r\n");
return XST_FAILURE;
}
rc= f_write(&fil,(void*)SourceAddress,LengthBytes,&bw);
if(rc){
xil_printf("Write File To SD Card Failed \r\n");
return XST_FAILURE;
}
rc= f_lseek(&fil, fil.fsize);
if(rc){
return XST_FAILURE;
}
rc= f_close(&fil);
if(rc){
return XST_FAILURE;
}
return XST_SUCCESS;
}
FatFs模块主要是设置其编译选项,如设置编译复杂度宏_FS_MINIMIZE。支持长文件名称宏_MAX_LFN等。依据需求对比ff.h里面的凝视或说明手冊设置就可以。
底层IO接口,由用户在diskio.c函数中实现,主要是实现:
① SD卡初始化。通过disk_initialize函数完毕,主要实现图12所列的SD卡初始化流程。
② 读数据,通过disk_read实现,从SD卡读取若干扇区的数据。
③ 写数据,通过disk_write实现,向SD卡写入若干扇区的数据。
Xilinxxilffsv3.0文件系统库眼下採用ADMA2数据传输。用轮询状态的方式推断数据传输情况,本用于FSBL从SD卡搬运启动镜像,在实际使用的过程中可改为中断的方式释放CPU资源。
在驱动调试的过程中经常会遇到SD卡一直写保护的现象,这样的现象产生的原因通常是:a)TF卡没有WP引脚,可是在Vivado Block Design中配置ZYNQ时为其配置了该引脚导致误判;b)Linux驱动默认会一直推断硬件WP状态,在操作TF卡时应凝视该功能。
应用笔记介绍FAT32文件系统、Zynq SD控制器特点、FatFs文件系统和其在Zynq平台上的实现,希望对有兴趣了解文件系统及SD卡底层行为的同行起到抛砖引玉的作用。Xilinx为其SD控制器提供全套的SDK支持包、Uboot驱动和Linux驱动程序,并在Wiki中有具体的驱动使用说明文档。
如有问题可增加QQ群300148644共同探讨。
标签:bytes 填充 超过 hello 关心 move out 分区 text
原文地址:http://www.cnblogs.com/gccbuaa/p/7258394.html