sunwise123的个人空间 https://bbs.21ic.com/?912015 [收藏] [复制] [RSS]

日志

FATFS文件系统说明

已有 3211 次阅读2016-12-31 16:40 |个人分类:嵌入式软件|系统分类:嵌入式系统

FatFs Module 是一种完全免费开源的FAT 文件系统模块,专门为小型的嵌入式系统而 
设计。它完全用标准C 语言编写,且完全独立于I/O 层,可以移植到 8051、PIC、AVR、SH、 
Z80、H8 和ARM 等系列单片机上且只需做简单的修改。它支持FATl2、FATl6 和FAT32, 
支持多个存储媒介,有独立的缓冲区,可以对多个文件进行读/写。
  FatFs Module 有个简化版本Tiny-FatFs,它跟完全版FatFs 不同之处主要有两点:
(1) 占用内存更少,只要1 KB RAM; 
(2) 1 次仅支持 1 个存储介质。
完全版FatFs 和Tiny-FatFs 的用法一样,仅仅是包含不同的头文件,本文主要以完全版 
讲解FatFs 的使用。
1.2 特性
(1)Windows 兼容的FAT 文件系统; 
(2)平台无关,容易移植; 
(3)代码量小; 
(4)多种配置选项: 
   支持多卷(物理驱动器或分区); 
   多个ANSI/OEM 代码页包括DBCS; 
   支持长文件名,ANSI/OEM 或Unicode; 
   支持RTOS; 
   支持多种扇区大小; 
   只读、最小化的API 和I/O 缓冲区等。
1.3 应用
FatFs Module 一开始就是为了能在不同的单片机上使用而设计的,所以具有良好的层次 
结构,如图 1.1 所示。
 
  最顶层是应用层,使用者无需理会FatFs Module 的内部结构和复杂的FAT 协议,只需 
要调用FatFs Module 提供给用户的一系列应用接口函数,如f_open,f_read,f_write 和 f_close 
等,就可以像在PC 上读/写文件那样简单。
  中间层FatFs Module 实现了FAT 文件读/写协议。FatFs Module 的完全版提供的是ff.c、 
ff.h,简化版Tiny-FatFs 提供的是tff.c、tff.h 。除非有必要,使用者一般不用修改,使用时将 
需要版本的头文件直接包含进去即可。
  需要使用者编写移植代码的是FatFs Module 提供的底层接口,它包括存储媒介读/写 
接口Disk I/O 和供给文件创建修改时间的实时时钟。
  本文讲解时移植硬件平台为ZLG 公司的SmartCortexM3-1700 和普通U 盘。LPC1768 
是一款32 位 Cortex-M3 内核的单片机,具有多达64 KB 的SRAM、512 KB 的内部Flash 和 
丰富的外设。软件平台是Keil 集成开发环境。
1.3.1 FatFs 软件包中相关文件
1. 平台无关
(1)ffconf.h FatFs 模块配置文件
(2)ff.h FatFs 和应用模块公用的包含文件
(3)ff.c FatFs 模块
(4)diskio.h FatFs and disk I/O 模块公用的包含文件
(5)integer.h 数据类型定义
(6)option 可选的外部功能
2. 平台相关(不属于 FatFs 需要由用户提供)
(1)diskio.c FatFs 与disk I/O 模块接口层文件
1.3.2 FatFs 应用范围
支持FAT12、FAT16 和FAT32; 
可打开的文件:无限制,依赖于有效的存储器; 
支持最多 10 个卷; 
文件大小:与FAT 类型有关(upto 4G-1 bytes); 
卷大小:与FAT 类型有关(upto 2T bytes on 512 bytes/sector); 
簇大小:与FAT 类型有关(upto 64K bytes on 512 bytes/sector); 
扇区大小:与FAT 类型有关(upto 4K bytes)。
FatFs 模块在移植时需先注意以下两点:
•ANSI C
FatFs 模块是用ANSI C 编写的中间件,只要编译器遵循ANSI C,它都是平台无关的。
•整型大小
FatFs 假定 char/short/long 的长度为8/16/32 位,而int 为 16 位或 32 位,这些相应的定 
义位于integer.h 文件。这在大多数的编译器上都不会是问题,但是当与预定义的内容发生冲 
突时,需要用户注意。
1.3.3 FatFs 配置
文件系统的配置项都在ffconf.h 文件之中。
(1) _FS_TINY :这个选项在R0.07 版本之中开始出现,在之前的版本都是以独立的C
文件出现,现在通过一个宏来修改使用起来更方便;决定在文件数据传输中使用哪种扇区缓冲区 
(2) _FS_MINIMIZE、_FS_READONLY、_USE_STRFUNC、_USE_MKFS、 
_USE_FORWARD 这些宏是用来对文件系统进行裁剪的,下面的 1.3.4 小节中有详细介绍; 
(3) _CODE_PAGE :本选项用于设置语言码的类型,对应的字库可以在网上下载
(4) _USE_LFN :取值为0~3,主要用于长文件名的支持及缓冲区的动态分配: 
0:不支持长文件名; 
1:支持长文件名存储的静态分配,一般是存储在BSS 段; 
2:支持长文件名存储的动态分配,存储在栈上; 
3:支持长文件名存储的动态分配,存储在堆上。 
(5) _MAX_LFN :可存储长文件的最大长度,其值一般为(12~255),但是缓冲区一
般占(_MAX_LFN + 1) * 2 bytes; 
(6) _LFN_UNICODE :为1 时才支持unicode 码; 
(7) _FS_RPATH :R0.08a 版本改动配置项,取值范围0~2: 
0:去除相对路径支持和函数; 
1:开启相对路径并且开启f_chdrive()和 f_chdir()两个函数; 
2:在1 的基础上添加f_getcwd()函数。
(8) _VOLUMES :支持的逻辑设备数目; 
(9) _MAX_SS :扇区缓冲的最大值,其值一般为512; 
(10) _MULTI_PARTITION :定义为1 时,支持磁盘多个分区; 
(11) _USE_ERASE :R0.08a 新加入的配置项,设置为 1 时,支持扇区擦除; 
(12) _WORD_ACCESS :如果定义为1,则可以使用word 访问; 
(13) _FS_REENTRANT :定义为1 时,文件系统支持重入,但是需要加上跟操作系统 
信号量相关的几个函数,函数在 syscall.c 文件中; 
(14) _FS_SHARE :文件支持的共享数目。
  FatFs 只要求提供FatFs 模块所必需的底层磁盘I/O 函数,如果存在一个可工作的目标磁 
盘模块,你仅需将编写的新函数附加到FatFs 模块上,如果没有,则需要提供其它磁盘模块 
或者从头编写底层驱动。FatFs 中所有定义的函数并不总是必需的,例如,在只读配置模式 
下,磁盘写函数是不需要的。表 1.1 显示了FatFs 的函数需要依赖于配置选项。
  
1.3.4 FatFs API 函数选择
  通过配置选项对API 函数进行选择(剪裁)以减小模块代码大小
1.3.5 路径名格式
  FatFs 模块上使用的路径名格式类似于DOS/Windows 下的文件名,格式如下:
"[drive#:][/]directory/file"
  FatFs 模块支持长文件名 (LFN)和DOS 8.3 文件名 (SFN)。当使能LFN 特性时 (_USE 
_LFN > 0),可以使用长文件名,子目录用‘\ ’或者‘/ ’隔开,这与DOS/Windows API 函 
数接口是相同的方式,不同的是逻辑驱动器用数字带一个冒号来指定的。当一个驱动器号被 
忽略时,默认为驱动器0 或者当前驱动器。控制字符(\0~\x1F )被认为是路径名的末尾。 
首位或中间嵌入的空格是合法的,当配置为LFN 时被看作是名字的一部分,配置为非LFN 
时被视为路径名的末尾。空格和点号被忽略。
  默认配置下(_FS_RPATH == 0 ),FatFs 没有一个像操作系统面向文件系统的当前目录 
的概念。卷上的所有对象总是以根目录下的完整路径名来指定,不允许点目录名。标题分隔 
符’/’被忽略,它可以存在或省略,默然的驱动器号为0。
  当使能相对路径时(_FS_RPATH == 1 ),如果存在标题分隔符,指定的路径是指相对 
于根目录,如果没有标题分隔符,指定目录是指相对于用f_chdir 函数设置的当前目录,路 
径名中允许使用点名称。默认的驱动器是用 f_chdrive 函数设定的当前驱动器。
1.3.6 关于长文件名
FatFs 从0.07 版本开始支持长文件名(LFN)。在调用文件函数时,一个文件的两个文 
件名(SFN 与LFN)是通用的,除了f_readdir 函数。支持长文件特性将需要一个额外的工 
作缓冲区,此缓冲区的大小可以通过设置_MAX_LFN 来以可用的内存大小相符。因为长文 
件名可长达255 个字符,因此_MAX_LFN 应该设置为255 来支持全特性的LFN 选项。当工 
作缓冲区的大小容不下给出的文件名时文件函数就会因为FR_INVALID_NAME 而调用失 
败。
当使能LFN,模块增加的大小由编码页(Code Page)类型决定。日语、中文与韩国语拥有成千上万的字词,因 
需要一个巨大的OEM-Unicode 双向转换表,模块的大小将大大的增大。
注:FAT 文件系统的LFN 特性是微软公司的专利。当在商用产品上使用时,根据最终目的的不同可
能需要获得微软的许可证。
 1.3.7 重入
对不同卷的文件操作总是可以同时地工作,而与重入设置无关。而对于同一个卷的重入 
访问可以通过使能_FS_REENTRANT 选项。此时,在 ff.c 中的与平台相关的锁定函数必须 
为每个RTOS 重新编写。如果一个文件函数调用时其访问的卷正被另一个线程使用,则此 
访问将阻塞直到该卷解锁。如果等待时间超过了_TIMEOUT 毫秒,则函数将因FR_TIMEOUT 
而终止。某些RTOS 可能不支持超时操作。
f_mount 与f_mkfs 函数是个例外,这些函数对于同一个卷不会重入。当使用这些函数时, 
其它线程必须关闭此卷中相应的文件,避免对此卷的访问。
注意此部分描述的是FatFs 自身的重入,与底层磁盘I/O 的重入无关。
1.3.8 执行有效的文件访问
  为了在小型的嵌入式系统中得到优秀的读写效率,应用程序程序员需要可考虑FatFs 究 
竟做了什么。磁盘中的数据是通过下面的方式来被f_read 函数传送。
  文件I/O 缓冲区(file I/O buffer)表示一个将被读/写数据的扇区的缓冲区。扇区缓冲区 
可以是每个文件对象私有的,或者是文件系统共享的,缓冲区配置选项_FS_TINY 决定在文 
件数据传输中使用哪种扇区缓冲区。当选择小缓冲区(1),数据内存的使用量将降低到每 
个文件对象 512 字节。在这种情况下,FatFs 只使用一个扇区缓冲区来进行文件数据传输以 
及FAT/ 目录访问。配置为小缓冲区的缺点是:每次文件数据传输时FAT 数据缓冲都会丢失 
而必须从一个簇的边界开始重新载入数据。不过从其体面的表现与少内存消耗这方面来考 
虑,这对于多数的应用也是合适的。
  使用扇区对齐的方式来进行读写访问可以避免缓冲区数据传输,并且读写效率将被 
提升。除了效率以外,在tiny 配置的情况下FAT 快速缓存数据在文件数据传输时不会刷新, 
所以可以用小内存消耗来达到非tiny 配置相同的性能。
1.3.9 临界区
当对FAT 文件系统的写操作由于意外而中断,如突然断电,不正确的磁盘移除或不可 
恢复的磁盘错误,FAT 结构可能被毁坏。
1.3.10 FatFs 的其它特性和新进展
(1) 支持并发操作;
在多任务操作系统中,各个任务是并发的。当它们要同时访问文件系统时,先要获得同 
步对象。比如在uCOS 中,可以采用互斥信号量来同步。在f_mount()时,创建同步对象, 
在check_mount()和validate()函数调用时,先申请同步对象,若是其它任务在使用文件系统, 
则在同步对象上等待。任务完成后,再释放同步对象。这个功能与操作系统的任务同步特性 
相关,以后如果要使用这个特性的话在详细分析。
(2) 支持文件的共享打开(主要是多次以读的方式打开);
这是FatFs 作者在3 月份新上传的R008 Rev1 版本里新增加的功能:在ffconf.h 中增加 
了_FS_SHARE 共享数目定义。在 ff.h 增加了:文件共享信息结构体定义,并在文件系统结 
构体中使用,在ff.c 中增加了5 个函数。
(3) 支持文件的快速定位;
内存中划一块缓冲区用于存储 文件的簇链映射图,以方便查找簇链。稍微阅读了以下 
源代码,其实现方法是这样的:当给出参数 ofs == CREATE_LINKMAP 的时候,在tbl 所指 
向的内存区域建立新的簇链映射。
表的第一项是整个映射表的长度,以后每两项为一对:前者存储相邻簇的数目,后者存 
储相邻簇的起始簇号。举个例子,某个文件占据 5、6、7、8、15、16、17 共 7 个簇,则需 
要两对表项。分别是(4,5)和(3,15)两项。以后就可以利用该簇链映射图实现文件的 
快速定位了,不用沿着簇链一项一项找下去,最后实现定位。
(4) 支持长文件名缓冲区的动态分配; 
(5) 添加函数 f_getcwd(); 
(6) 添加_USE_ERASE ;
将以前的 auto_mount()改成了现在的chk_mounted()添加部分功能使文件系统更适合多 
逻辑设备数目。
1.3.11 程序移植
移植FatFs 主要分为三步:
(1) 数据类型:在integer.h 里面去定义好数据的类型。这里需要了解你用的编译器的数 
据类型,并根据编译器定义好数据类型。 
(2) 配置:打开 ffconf.h (我用的FatFs,不是Tiny,可以在此头文件中进行定义),文 
件系统的配置裁剪等均在此头文件中进行定义配置。 
(3) 函数编写:打开diskio.c,进行底层驱动编写,实际上需要编写6 个接口函数,如 
图1.6 所示。
 
1.3.12 diskio.c函数编写
1、disk_initialize
初始化磁盘驱动器 
2、disk_status
返回当前磁盘驱动器的状态 
3、disk_read 
从磁盘驱动器上读取扇区
4、disk_write 
向磁盘写入一个或多个扇区 
5、disk_ioctl 
控制设备指定特性和除了读/写外的杂项功能
6、get_fattime 
获取当前时间
1.3.13 FatFS软件包提供的API函数
 1、f_mount:注册/注销一个工作区
2、f_open:打开/创建一个文件
3、f_close:关闭一个文件
4、f_read:读文件
5、f_write:写文件
6、f_lseek:移动读/写指针,扩展文件大小
7、f_truncate:截断文件大小
8、f_sync:刷新缓冲区
9、f_opendir:打开一个目录
10、f_readdir:读取目录
11、f_getfree:获取空闲簇
12、f_stat:获取文件状态
13、f_mkdir:创建一个新目录
14、f_unlink:删除一个文件
15、f_chmod:改变一个文件或目录的属性
16、f_utime:改变一个文件或目录的时间戳
17、f_rename:重命名一个对象
18、f_mkfs:格式化
19、f_forward:读取文件数据转移到数据流设备
20、f_chdir:改变驱动器的当前目录
21、f_chdrive:改变当前驱动器
22、f_getcwd:检索当前目录
23、f_gets:从文件中读取字符串
24、f_putc:从文件中写一个字符
25、f_puts:往文件中写一个字符串
26、f_printf:往文件中写入格式化字符串


路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)