前言:
FATFS作为一个优秀的文件系统开源项目,具有高性能、易移植的特点。本文主要分二个部分:FATFS的架构介绍、源码剖析。
开发文档下载地址:https://download.csdn.net/download/wjb123sw99/15663489?spm=1001.2014.3001.5501
架构:
FATFS处于应用层和磁盘IO层之间,对应用层提供的接口封装风格与标准C的文件操作接口风格一致,应用程序只需进行少量的修改即可使用。对与磁盘IO层,FATFS完全与其分开,开发人员需要自己实现FATFS中diskio.h中声明的磁盘控制函数,其架构如下:
源码剖析:
FATFS源代码精简,只包括diskio.h、diskio.c、ff.h、ff.c、ffconf.h、ffsystem.c、ffunicode.h七个源码文件,其调用顺序如下:
diskio:
diskio为FATFS项目的磁盘接口模块,为FATFS提供磁盘控制函数。
磁盘控制函数返回值定义:
DRESULT定义 | 描述 |
RES_OK | 成功 |
RES_ERROR | 读写失败 |
RES_WRPRT | 写保护 |
RES_NOTRDY | 未准备好 |
RES_PARERR | 参数错误 |
磁盘状态定义:
DSTATUS定义 | 描述 |
STA_NOINIT | 未初始化驱动器 |
STA_NODISK | 驱动器中没有介质(未找到物理磁盘) |
STA_PROTECT | 写保护 |
初始化驱动函数:
接口定义 | DSTATUS disk_initialize (BYTE pdrv); |
参数说明 | 输入:pdrv:物理驱动器号,用于识别驱动器。 返回值:成功返回0,失败返回DSTATUS定义错误码 |
备注 | 该函数用于初始化驱动器,开发者可在此处定义磁盘驱动初始化逻辑,如果磁盘驱动无需初始化则直接返回0。 |
获取驱动状态函数:
接口定义 | DSTATUS disk_status (BYTE pdrv); |
参数说明 | 输入:pdrv:物理驱动器号,用于识别驱动器。 返回值:成功返回0,失败返回DSTATUS定义错误码 |
备注 | 该函数用于获取驱动器状态,如果有异常则返回DSTATUS定义的异常类型,如果正常则返回0。 |
磁盘读函数:
接口定义 | DRESULT disk_read (BYTE pdrv, BYTE* buff, LBA_t sector, UINT count); |
参数说明 | 输入:pdrv:物理驱动器号,用于识别驱动器。 buff:用于存储读取数据的缓存,大小为count*扇区大小 sector:读取数据起始扇区号 count: 读取扇区个数 输出:buff: 读取的数据 返回值:成功返回0,失败返回DRESULT定义错误码 |
备注 | FATFS扇区大小可进行配置,默认扇区大小为512字节。一般情况下设备的扇区大小是固定的即FF_MIN_SS == FF_MAX_SS。此时disk_read函数读取count参数恒为1,即单次读取数据大小为磁盘扇区大小。Sector扇区号从0开始计数,例如8GB的磁盘,扇区号取值范围在[0, 16777216) |
磁盘写函数:
接口定义 | DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count); |
参数说明 | 输入:pdrv:物理驱动器号,用于识别驱动器。 buff:待写入数据,大小为count*扇区大小 sector:写入数据起始扇区号 count: 读取扇区个数 返回值:成功返回0,失败返回DRESULT定义错误码 |
备注 | FATFS扇区大小可进行配置,默认扇区大小为512字节。一般情况下设备的扇区大小是固定的即FF_MIN_SS == FF_MAX_SS。此时disk_write函数读取count参数恒为1,即单次读取数据大小为磁盘扇区大小。sector扇区号从0开始计数,例如8GB的磁盘,扇区号取值范围在[0, 16777216) |
磁盘命令函数:
接口定义 | DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); |
参数说明 | 输入:pdrv:物理驱动器号,用于识别驱动器。 cmd:命令 buff:发送数据 输出:buff:接收数据 返回值:成功返回0,失败返回DRESULT定义错误码 |
备注 | FATFS通过下发命令实现特点功能,开发人员需要根据实际情况针对不同命令进行实现。 |
cmd命令定义:
cmd定义 | 描述 |
CTRL_SYNC | disk_ioctl接收到该命令,如果磁盘具有缓存的功能,则需要将缓存数据立即刷新到磁盘介质中存储。如果磁盘没有缓存数据的功能则无需进行任何操作。 |
GET_SECTOR_COUNT | disk_ioctl接收到该命令,需要在buff中输出磁盘扇区的数量 |
GET_SECTOR_SIZE | disk_ioctl接收到该命令,需要在buff中输出磁盘扇区的大小,仅当FF_MAX_SS> FF_MIN_SS时才需要此命令。 |
GET_BLOCK_SIZE | disk_ioctl接收到该命令,可以选择在buff中填充擦除块的大小,返回在[0, 32768],也可以选择不做任何操作。 |
CTRL_TRIM | disk_ioctl接收到该命令,可以选择擦除buff中指定的扇区号数组,也可以不做任何操作。 |
FF:
ff为FATFS项目提供各种文件系统功能函数。
文件系统功能函数定义:
FRESULT定义 | 描述 |
FR_OK | 成功 |
FR_DISK_ERR | 磁盘错误,底层disk_read、disk_write或disk_ioctl函数调用发生错误时返回。 |
FR_INT_ERR | 程序断言错误,该问题大多数情况下是由于工作区堆栈溢出导致 |
FR_NOT_READY | 文件系统没有准备好,该问题是由于调用disk_initialize报错导致的 |
FR_NO_FILE | 没有该文件 |
FR_NO_PATH | 没有该路径 |
FR_INVALID_NAME | 无效名称,请检查编码问题或者FF_MAX_LFN小于文件名 |
FR_DENIED | 禁止访问,可能是文件权限问题或者磁盘已满 |
FR_EXIST | 对象已存在 |
FR_INVALID_OBJECT | 无效对象,可能是句柄已关闭或者磁盘驱动未准备好 |
FR_WRITE_PROTECTED | 写保护 |
FR_INVALID_DRIVE | 无效驱动 |
FR_NOT_ENABLED | 驱动器工作区尚未未通过f_mount函数注册 |
FR_NO_FILESYSTEM | 没有有效的FAT卷,该错误建议重新格式化磁盘文件系统 |
FR_MKFS_ABORTED | 调用f_mkfs函数报错,可能是由于f_mkfs入参错误,或者是磁盘IO提供的可用扇区太小(>=128个扇区) |
FR_TIMEOUT | 超时,不能在规定的时间内获得访问卷的授权 |
FR_LOCKED | 根据文件共享策略拒绝此操作 |
FR_NOT_ENOUGH_CORE | 工作缓冲区长度不足 |
FR_TOO_MANY_OPEN_FILES | 打开文件数 > FF_FS_LOCK |
FR_INVALID_PARAMETER | 无效参数 |
FATFS提供的f_open、fclose等文件操作函数与POSIX标准提供的fopen、fclose等文件操作函数调用方法基本一致,应用程序只需进行少许修改即可应用,例子如下:
#include <stdio.h>
#include "ff.h"
int main()
{
FATFS fs0; /* Fatfs驱动句柄 */
FIL fsrc; /* 文件句柄 */
BYTE buffer[4096];
FRESULT fr; /* FatFs函数返回值 */
UINT br; /* File read/write count */
/* 挂载驱动 */
f_mount(&fs0, "0:", 0);
/* 打开文件句柄 */
fr = f_open(&fsrc, "0:file.bin", FA_WRITE | FA_CREATE_ALWAYS);
if (fr)
{
f_unmount("0:");
return (int)fr;
}
/* 写数据 */
fr = f_write(&fsrc, buffer, sizeof buffer, &br);
if (fr)
{
f_close(&fsrc);
f_unmount("0:");
return (int)fr;
}
if (br != sizeof buffer)
{
/* 实际写入字节数不对 */
f_close(&fsrc);
f_unmount("0:");
return -1;
}
/* 关闭文件句柄 */
f_close(&fsrc);
/* 卸载驱动*/
f_unmount("0:");
return (int)fr;
}
POSIX标准的fopen函数文件标志与FATFS的f_open函数文件标志对应关系如下:
POSIX mode定义 | FATFS mode 定义 |
"r" | FA_READ |
"r+" | FA_READ | FA_WRITE |
"w" | FA_CREATE_ALWAYS | FA_WRITE |
"w+" | FA_CREATE_ALWAYS | FA_WRITE | FA_READ |
"a" | FA_OPEN_APPEND | FA_WRITE |
"a+" | FA_OPEN_APPEND | FA_WRITE | FA_READ |
"wx" | FA_CREATE_NEW | FA_WRITE |
"w+x" | FA_CREATE_NEW | FA_WRITE | FA_READ |
ffconf:
ffconf为FATFS的功能配置模块,开发者可以根据需求修改对应参数,
参数名 | 描述 |
FFCONF_DEF | 配置文件修订ID 如果ffconf配置文件中定义的FFCONF_DEF与ff.h中定义的FF_DEFINED不一致,则会报错,代码如下: #if FF_DEFINED != FFCONF_DEF #error Wrong configuration file (ffconf.h). #endif |
FF_FS_READONLY | 配置读写模式 当该参数设置为0时表示FATFS支持读写,当该参数设置为1是表示FATFS为只读模式。 |
FF_FS_MINIMIZE | 配置FATFS最小化级别 0:基本功能完全开启。 1: 删除f_stat (), f_getfree (), f_unlink (), f_mkdir (), f_truncate()和f_rename () 2: 在1基础上,删除f_opendir(), f_readdir()和f_closedir()。 3: 在1、2基础上,删除f_lseek()。 |
FF_USE_STRFUNC | 配置字符串函数f_gets(), f_putc(), f_puts() and f_printf(). 0:不支持这些函数 1:支持这些函数,但不支持 LF-CRLF 2:支持这些函数,且支持 LF-CRLF |
FF_USE_FIND | 配置文件检索函数 f_findfirst() 、f_findnext() 0:不支持这些函数 1:支持这些函数,匹配fname 主要名称 2:支持这些函数,同时检索altname替代名称 相关信息在结构体FILINFO中有定义, #if FF_USE_LFN TCHAR altname [FF_SFN_BUF +1]; / *替代对象名称* / TCHAR fname [FF_LFN_BUF +1]; / *主要对象名称* / #else |
FF_USE_MKFS | 配置f_mkfs()函数 0:不启用 1:启用 |
FF_USE_FASTSEEK | 配置快速寻道功能,启用时会在FIL句柄中建立映射表加快查找 0:不启用 1:启用 |
FF_USE_EXPAND | 配置f_expand函数 0:不启用 1:启用 |
FF_USE_CHMOD | 配置 f_chmod() 和f_utime()函数 0:不启用 1:启用 |
FF_USE_LABEL | 配置f_getlabel()和f_setlabel()函数 0:不启用 1:启用 |
FF_USE_FORWARD | 配置f_forward()函数 0:不启用 1:启用 |
FF_CODE_PAGE | 此选项指定要在目标系统上使用的OEM代码页。 |
FF_USE_LFN | 配置长文件名支持 0:不支持长文件名。FF_MAX_LFN没有作用。 1:在BSS上开启FF_MAX_LFN和静态工作缓冲区。但不是线程安全的。 2:在堆栈上开启FF_MAX_LFN与动态工作缓冲区。 3:在堆上启用FF_MAX_LFN和动态工作缓冲区。 |
FF_MAX_LFN | 最大文件名 |
FF_LFN_UNICODE | 切换字符编码 0: ANSI/OEM (TCHAR = char) 1: UTF-16中的Unicode (TCHAR = WCHAR) 2: Unicode的UTF-8 (TCHAR = char) 3: Unicode在UTF-32 (TCHAR = DWORD) |
FF_LFN_BUF | 当开启检索功能时,F_LFN_BUF定义了FILINFO结构体中fname的缓存长度 |
FF_SFN_BUF | 当开启检索功能时,FF_SFN_BUF定义了FILINFO结构体中altname的缓存长度 |
FF_STRF_ENCODE | 用于转换字符串IO函数的字符编码 0: ANSI/OEM 1: UTF-16LE格式的Unicode 2: UTF-16BE格式的Unicode 3: UTF-8格式的Unicode |
FF_FS_RPATH | 配置相对路径支持 0: 禁用相对路径 1: 启用相对路径。f_chdir()和f_chdrive()可用 2: 启用相对路径。f_chdir()和f_chdrive()、 f_getcwd()可用 |
FF_VOLUMES | 要使用的卷(逻辑驱动器)的数量,取值范围[1, 10] |
FF_STR_VOLUME_ID | 自定义卷ID 0: 关闭 1: 开启 |
FF_VOLUME_STRS | 自定义卷名 |
FF_MULTI_PARTITION | 配置驱动器上卷数量 0:只绑定一个卷号 1:支持绑定多个卷 |
FF_MIN_SS | 扇区最小字节数,一般FF_MIN_SS==FF_MAX_SS |
FF_MAX_SS | 扇区最大字节数,一般FF_MIN_SS==FF_MAX_SS |
FF_LBA64 | 配置支持64位LAB(逻辑区块地址) 0:不支持 1:支持 |
FF_MIN_GPT | 当FF_LBA64启动时,FF_MIN_GPT值等于GPT分区格式的最小扇区数 |
FF_USE_TRIM | 配置支持项ATA-TRIM 0:不支持 1:支持 |
FF_FS TINY | 配置小缓冲区 0:正常 1:小 |
FF_FS_EXFAT | 配置exFAT文件系统的支持 0:不支持 1:支持 |
FF_FS_NORTC | 切换时间戳配置 0:使用get_fattime()函数返回的时间戳 1:使用FF_NORTC_MON FF_NORTC_MDAY FF_NORTC_YEAR默认时间戳 |
FF_NORTC_MON | 默认月份 |
FF_NORTC_MDAY | 默认天 |
FF_NORTC_YEAR | 默认年份 |
FF_FS_NOFSINFO | 配置 f_getfree()函数 0:启用 1:禁止 |
FF_FS_LOCK | 配置文件锁定 0:关闭文件锁定功能 1:打开文件锁定功能 |
FF_FS_REENTRANT | 配置FatFs的可重入性 0:禁用重入。FF_FS_TIMEOUT和FF_SYNC_t不起作用。 1:启用重入。另外,用户提供的同步处理程序 |
FF_FS_TIMEOUT | 定义超时时间 |
FF_SYNC_t | 同步对象类型 |