FatFS简介

Posted on 2015-01-04 14:59  kp_liu  阅读(9612)  评论(0编辑  收藏  举报

1.1 简介

  随着信息技术的发展,当今社会的信息量越来越大,以往由单片机构成的系统简单地对
存储媒介按地址、按字节的读/写已经不能满足人们实际应用的需要,于是利用文件系统对
存储媒介进行管理成了今后单片机系统的一个发展方向。目前常用的文件系统主要有微软的
FATl2、FATl6、FAT32、NTFS 以及Linux 系统下的EXT2 和EXT3 等。由于微软Windows
的广泛应用,在当前的消费类电子产品中,用得最多的还是FAT 文件系统,如U 盘、MP3、
MP4 和数码相机等,所以找到一款容易移植和使用、占用硬件资源相对较小而功能又强大
的FAT 开源文件系统,对于单片机系统设计者来说是很重要的。

  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:往文件中写入格式化字符串

 

Copyright © 2024 kp_liu
Powered by .NET 8.0 on Kubernetes