FATFS 移植和配置分析

0. FATFS

  • FatFs 是用于小型嵌入式系统的通用 FAT/exFAT 文件系统模块。 FatFs 模块是按照 ANSI C (C89) 编写的,与磁盘 I/O 层完全分离。因此,它独立于平台。它可以集成到资源有限的小型微控制器中,例如 8051、PIC、AVR、ARM、Z80、RX 等。这里还提供用于微型微控制器的 Petit FatFs 模块

0.1 FATFS 的优势

    1. DOS/Windows 兼容的 FAT/exFAT 文件系统。
    1. 平台无关。易于移植。
    1. 程序代码和工作区的占用空间非常小。
    1. 支持的各种配置选项:
      • ANSI/OEM 或 Unicode 中的长文件名。
      • 支持 exFAT 文件系统、64 位 LBA 和 GPT 用于大容量存储。
      • RTOS 的线程安全。
      • 支持多卷 (物理驱动器和分区)
      • 支持可变扇区大小。
      • 支持多个代码页,包括 DBCS。
      • 支持只读、可选 API、I/O 缓冲区等…

0.2 FATFS 的框架

  • FatFs 模块是独立于平台和存储介质的文件系统层,它与物理设备完全分离,例如存储卡、硬盘和任何类型的存储设备。存储设备控制模块不是 FatFs 模块的任何部分,需要由实现者提供。 FatFs 通过一个简单的媒体访问接口控制存储设备,如下所示。下载中还提供了某些平台的示例实现

在这里插入图片描述

0.3 FATFS 的接口

0.3.1 介质访问接口 (Media Access Interface)

  • 介质访问接口用于对接底层介质驱动(如SD/MMC, SATA 等),在移植中,用介质驱动接口实现 FATFS 的介质访问接口

  • 存储设备接口

    disk_status - Get device status
    disk_initialize - Initialize device
    disk_read - Read data
    disk_write - Write data
    disk_ioctl - Control device dependent functions
  • 实时时钟接口
    get_fattime - Get current time

0.3.2 文件访问接口 (File Access Interface)

  • FATFS 实现了文件访问接口,这些接口由用户调用,用于读写或者控制文件

    f_open - Open/Create a file
    f_close - Close an open file
    f_read - Read data from the file
    f_write - Write data to the file
    f_lseek - Move read/write pointer, Expand size
    f_truncate - Truncate file size
    f_sync - Flush cached data
    f_forward - Forward data to the stream
    f_expand - Allocate a contiguous block to the file
    f_gets - Read a string
    f_putc - Write a character
    f_puts - Write a string
    f_printf - Write a formatted string
    f_tell - Get current read/write pointer
    f_eof - Test for end-of-file
    f_size - Get size
    f_error - Test for an error

0.3.3 目录访问接口(Directory Access Interface)

  • FATFS 实现了目录访问接口,用于创建删除目录
    f_opendir - Open a directory
    f_closedir - Close an open directory
    f_readdir - Read a directory item
    f_findfirst - Open a directory and read the first item matched
    f_findnext - Read a next item matched

0.3.4 文件和目录管理接口 (File and Directory Management Interface)

  • FATFS 实现了一类文件和目录通用的接口

    f_stat - Check existance of a file or sub-directory
    f_unlink - Remove a file or sub-directory
    f_rename - Rename/Move a file or sub-directory
    f_chmod - Change attribute of a file or sub-directory
    f_utime - Change timestamp of a file or sub-directory
    f_mkdir - Create a sub-directory
    f_chdir - Change current directory
    f_chdrive - Change current drive
    f_getcwd - Retrieve the current directory and drive

0.3.5 卷和系统配置接口(Volume Management and System Configuration Interface)

  • FATFS 提供了一系列卷相关的接口,支持获取系统配置
    f_mount - Register/Unregister the work area of the volume
    f_mkfs - Create an FAT volume on the logical drive
    f_fdisk - Create partitions on the physical drive
    f_getfree - Get free space on the volume
    f_getlabel - Get volume label
    f_setlabel - Set volume label
    f_setcp - Set active code page

0.4 FATFS 的能力

  • 只支持文件系统,FAT, FAT32(rev0.0) 和 exFAT(rev1.0)
  • 打开文件的数目无限制
  • 卷的限制,最多 10 个
  • 块大小,支持 512,1024,2048 和 4096 字节
  • 扇区总数,最少需要 128 个扇区
  • 卷的大小,32位 LBA 为 2^32 - 1,64 位 exFAT 文件系统基本上没有限制
  • 文件大小,FAT 卷最大 2^32 - 1 个字节,exFAT 卷基本上没有限制
  • 簇大小,FAT 卷上最多 128 个扇区,exFAT 卷上最多 16 MB

1. FATFS 的移植要求

  • 按照 ANSI C (C89) 编写移植代码,只用 exFAT 使用 C99
  • char 的大小必须是 8 位。
  • int 的大小以及整数提升必须是 16 位或 32 位。
  • short 和 long 的大小必须分别为 16 位和 32 位。 (仅在 C89 中)
  • 依赖 C99 的 string.h 和 stdint.h

1.1 实现 FATFS 的类型


BYTE
    8 位无符号整数,范围为 0 到 2^8 - 1.
WORD
    16 位无符号整数,范围为 0 到 2^16 - 1.
DWORD
   32 位无符号整数,范围为 0 到  2^32 - 1.
QWORD
    64 位无符号整数,范围为 0 到 2^64 - 1.
UINT
    unsigned int 的别名用于指定任何数字
WCHAR
    WORD 的别名用于指定 UTF-16 代码单元
TCHAR
    char、WCHAR 或 DWORD 的别名,用于指定字符编码单元
FSIZE_t
    DWORD 或 QWORD 的别名用于解决文件偏移和指定文件大小
LBA_t
    DWORD 或 QWORD 的别名用于寻址 LBA 中的扇区并指定扇区数.

1.2 实现 FATFS 的各依赖组件

  • 如图是 FATFS 文件操作从用户层到硬件的调用过程,为了移植 FATFS,我们需要实现这个过程中的各个依赖组件,
      1. FATFS module 通过复制 FATFS 代码完成
      1. Low level disk I/O layer 依赖具体介质的驱动实现
      1. Storage device 在具体的开发板上
        在这里插入图片描述

1.3 FATFS 支持多种介质

  • 如下图所示,有两种 FATFS 移植方式,一是 FATFS 对接一种读写介质(SPI-SD),这个时候直接用介质读写接口实现 disk_io 接口即可,二是 FATFS 对接多种读写介质,这个时候需要一个粘合功能,支持 disk_io 在下发读写命令时动态判断当前读写的介质类型和位置
    在这里插入图片描述

1.4 FATFS 移植需要实现的函数

1.4.1 基本 disk_io 函数

  • 有些时候,介质可能是只读的,只需要实现下面三个函数
disk_status
disk_initialize
disk_read

1.4.2 写操作 disk_io 函数

  • FF_FS_READONLY == 0,表示介质可以写,这时候还需要实现写相关的函数,写介质和同步介质
disk_write
get_fattime
disk_ioctl (CTRL_SYNC)
  • FF_USE_MKFS == 1,表示可以创建文件系统,需要实现下面的方法,支持获取介质的块总数和块大小
disk_ioctl (GET_SECTOR_COUNT)
disk_ioctl (GET_BLOCK_SIZE)
  • FF_MAX_SS != FF_MIN_SS,FF_MIN_SS 定义最小扇区大小,FF_MAX_SS 定义最大扇区大小,两者用于指定 disk_read 和 disk_write 工作的扇区范围,当扇区数目大于1,需要实现方法,获取扇区的大小
disk_ioctl (GET_SECTOR_SIZE)
  • FF_USE_TRIM == 1,表示移除文件时强制擦除扇区,这个是 SSD 上具有的一种叫 ATA-TRIM 的功能,用于回收设备上未使用的块

  • FATFS 的 diskio 支持一系列标准命令,在使用前要理解这些命令的含义

    • CTRL_SYNC, 确保设备已完成挂起的写入过程。如果磁盘 I/O 层或存储设备具有回写式缓存,则必须立即将脏缓存数据提交到介质。如果在 disk_write 函数中完成了对介质的每个写入操作,则此命令无需执行任何操作。
    • GET_SECTOR_COUNT, 检索驱动器上可用扇区的数量,最大允许的 LBA + 1,进入按 buff 指向的 LBA_t 变量。f_mkfs和f_fdisk函数使用此命令来确定要创建的卷/分区的大小。当FF_USE_MKFS == 1 时需要它。
    • GET_SECTOR_SIZE, 将扇区大小(通用读/写的最小数据单位)检索到按 buff 指向的 WORD 变量中。有效扇区大小为 512、1024、2048 和 4096。仅当FF_MAX_SS > FF_MIN_SS时才需要此命令。当 FF_MAX_SS == FF_MIN_SS时,将永远不会使用此命令,读/写函数必须以 FF_MAX_SS 字节/扇区为单位工作。
    • GET_BLOCK_SIZE, 以闪存介质扇区为单位的擦除块大小检索到按 buff 指向的 DWORD 变量中。允许的值为 1 到 32768,2 的幂。如果值为未知或非闪存介质,则返回 1。此命令仅由f_mkfs函数使用,它尝试在建议的块边界上对齐数据区域。当FF_USE_MKFS == 1 时需要它。请注意,FatFs没有任何闪存转换层(FTL)。磁盘 I/O 放置器或存储设备中必须包含 FTL
    • CTRL_TRIM,通知磁盘 I/O 铺设者或存储设备不再需要扇区块上的数据,并且可以擦除这些数据。扇区块在以 buff 指向的LBA_t数组 {<Start LBA>, <End LBA>} 中指定。这是与 ATA 设备的修剪相同的命令。如果此功能不受支持或不是闪存设备,则此命令无需执行任何操作。FatFs 不会检查结果代码,即使扇区块没有被很好地擦除,文件功能也不会受到影响。此命令在删除集群链和f_mkfs函数中调用。当FF_USE_TRIM == 1 时需要它。

1.4.3 Unicode 支持

  • FF_USE_LFN != 0 表示支持长文件名(LFN),此时 ffunicode.c 需要被加入编译,在栈上使用长文件名可能会造成溢出,在堆上使用长文件名功能则需要支持动态内存分配

      1. FF_USE_LFN = 1,Enable LFN with static working buffer on the BSS. Always NOT thread-safe
      1. FF_USE_LFN = 2,Enable LFN with dynamic working buffer on the STACK.
      1. FF_USE_LFN = 3,Enable LFN with dynamic working buffer on the HEAP.
  • 需要实现 unicode 相关函数

ff_uni2oem
ff_oem2uni
ff_wtoupper
  • FF_FS_REENTRANT == 1,此选项切换 FatFs 模块本身的重入(线程安全)。对不同卷的文件/目录访问始终是可重入的,并且无论此选项如何,它都可以同时工作,但是,卷管理功能 f_mount、f_mkfs 和 f_fdisk 始终不可重入。只有对同一卷的文件/目录访问,换句话说,每个文件系统对象的独占使用,都在此函数的控制之下。要启用此功能,还需要将用户提供的同步处理程序 ff_req_grant、ff_rel_grant、ff_del_syncobj 和 ff_cre_syncobj 添加到项目中。 ffsystem.c 中提供了示例代码
ff_cre_syncobj
ff_del_syncobj
ff_req_grant
ff_rel_grant
  • FF_USE_LFN == 3,依赖动态内存分配
ff_mem_alloc
ff_mem_free

2. FATFS 的 Unicode 支持

  • 默认情况下,即使在 LFN 配置中,FatFs 也使用 API 上设置的 ANSI/OEM 代码。 FatFs 还可以通过配置选项 FF_LFN_UNICODE 将 API 上的字符编码切换为 Unicode。这意味着 FatFs 符合功能齐全的 LFN 规范。数据类型 TCHAR 指定 API 上的路径名称字符串是 char(ANSI/OEM 或 UTF-8)、WCHAR(UTF-16)或 DWORD(UTF-32)的别名,具体取决于该选项。有关详细信息,请参阅文件名中的说明。

  • 请注意,在为 Unicode API 配置 FatFs 时,代码页 FF_CODE_PAGE 的设置实际上没有任何意义。应设置为 437 以减小模块大小。但是,当 FF_STRF_ENCODE == 0 时,它仍然会影响字符串 I/O 函数的代码转换,并且还会影响与旧系统的向后兼容性。在这种情况下,如果认为code page 有问题,可能需要正确配置代码页

3. FATFS 的 exFAT 支持

  • exFAT(Microsoft 的扩展文件分配表)文件系统是 FAT/FAT32 文件系统的继承,广泛用于嵌入式系统、消费设备和便携式存储介质。它被 SDA(SD 协会)采用作为 SDXC 卡的文件系统,64 GB 及更大,并且它们以这种格式提供。因此,exFAT 是可移动媒体和 FAT 的标准文件系统之一。 exFAT 文件系统允许文件大小超过 FAT 文件系统允许的 4 GB 限制,并且还减少了一些文件系统开销,尤其是集群分配延迟。这些特性允许记录大数据而不需要分成一些文件,并提高文件的写入吞吐量。

  • 请注意,exFAT 文件系统是 Microsoft Corporation 的专利。 FatFs 模块可以通过配置选项 FF_FS_EXFAT 打开或关闭 exFAT。为商业产品启用 exFAT 时,将需要 Microsoft 的许可证,具体取决于产品的最终目的地

3.1 64 位 LBA

  • LBA(逻辑块寻址)是一种寻址方法,用于指定数据块(称为扇区)在存储介质上的位置。它是一个简单的线性地址,从 0 作为第一个扇区开始,1 作为第二个扇区开始,依此类推。主机系统不需要考虑数据块在存储设备中是如何定位和管理的。 FatFs 仅支持 LBA 进行媒体访问。 32 位 LBA 是大多数 LBA 方案中的常见大小。它可以寻址多达 2^32 个扇区,512 字节/扇区中的 2 TB。当使用大于 2 TB 的存储设备时,将需要更大的扇区大小或 64 位 LBA 来寻址存储设备的整个扇区。

  • 默认情况下,FatFs 在 32 位 LBA 中工作以进行媒体访问。 FatFs 还可以通过配置选项 FF_LBA64 将其切换为 64 位 LBA。它还为存储设备上的分区管理启用 GPT(GUID 分区表)。有关 GPT 的更多信息,请参阅 f_mkfs 和 f_fdisk 函数

4. FATFS 的可重入问题

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值