1. 概述
    1.1. 简介
    FAT全称File Allocation Table,是一种由微软发明的文件系统。FAT文件系统考虑当时计算机性能有限,所以未被复杂化,此特性使它能用在嵌入式系统。
    FatFs是FAT文件系统的开源实现。FatFs是用C语言编写的,符合ANSI C (C89)标准,并且软件架构中把存储设备的操作接口独立出来,使得FatFs与平台无关,非常易于移植。FatFs官方网站http://elm-chan.org/fsw/ff/00index_e.html 。

1.2. 目的
本文档主要描述我司对FatFs的自定义配置,以及FatFs移植方法。方便工程师快速地把FatFs移植到不同的机型。本文以FatFs R0.13b版本为例进行介绍。

  1. FatFs介绍
    2.1. 配置项
    FatFs在编译前配置需要支持的功能,所有的配置项保存在文件ffconf.h中。下表列出了FatFs所有选项的默认值以及我司修改后的值。其中标蓝的项是与默认值不一样的项。
    配置项 含义 默认值 XGD配置值
    FF_FS_READONLY 使能或禁用与写相关函数,0是使能写函数 0 0
    FF_FS_MINIMIZE 基本API配置等级,0是最高等级,支持的API最多 0 0
    FF_USE_STRFUNC 是否使能字符处理函数,0是禁用 0 0
    FF_USE_FIND 使能或禁用在指定目录内搜索指定文件函数:f_findfirst和f_findnext,0是禁用 0 0
    FF_USE_MKFS 是否使能f_mkfs函数创建文件系统,0是禁用 0 1
    FF_USE_FASTSEEK 使能或禁用快速搜索功能,使能后,可以加快f_lseek、f_read和f_write函数执行,0是禁用 0 0
    FF_USE_EXPAND 使能或禁用f_expand函数,该函数可以为文件分配连续数据区域,0是禁用 0 0
    FF_USE_CHMOD 使能或禁用元数据控制函数:f_chmod和f_utime,0是禁用 0 0
    FF_USE_LABEL 使能或禁用卷标签API函数:f_getlabel和f_setlabel,0是禁用 0 0
    FF_USE_FORWARD 使能或禁用f_forward函数,0是禁用 0 0
    FF_CODE_PAGE 规定目标系统使用的OEM代码,如果该代码设置的不正确,可能会引起文件打开失败(跟文件名称编码相关) 932 437
    FF_USE_LFN 使能或禁用长文件名(LFN),0是禁用,1是使能并使用静态数组作为缓冲(非线程安全),2是使能并使用栈内存作为缓冲,3是使能并使用堆内存作为缓冲,使能后需要编译ffunicode.c。如果配置为0,文件和文件夹的名称最长只能支持8字节。 0 2
    FF_MAX_LFN 长文件名工作缓冲区大小,可以为12~255字节。当禁用长文件名时,此选项无效 255 31
    FF_LFN_UNICODE 使能或禁用Unicode。如果要使用Unicode(UTF16)字符串路径名,需要使能LFN和设置本选项为1。此选项还影响字符串I/O功能函数。如果禁用长文件名,此选项必须为0 0 0
    FF_LFN_BUF 255 255
    FF_SFN_BUF 12 12
    FF_STRF_ENCODE 使能Unicode API函数,包括f_gets(),f_putc(), f_puts,f_printf(),0是禁用 3 0
    FF_FS_RPATH 使能或禁用相对路径函数,0是禁用 0 0
    FF_VOLUMES 配置可用卷的数目 1 1
    FF_STR_VOLUME_ID 使能或禁用字符串卷标识,0是禁用 0 0
    FF_VOLUME_STRS 逻辑驱动器的字符串卷标识 “RAM”,“NAND”,“CF”,“SD”,“SD2”,“USB”,“USB2”,“USB3” “RAM”,“NAND”,“CF”,“SD”,“SD2”,“USB”,“USB2”,“USB3”
    FF_MULTI_PARTITION 使能或禁止多分区函数,0是禁用 0 0
    FF_MIN_SS 定义扇区大小,有效值为512、1024、2048、4096,需要根据硬件配置来定义,可定义为Flash的页大小。FF_MIN_SS定义最小扇区大小,FF_MAX_SS定义最大扇区大小。当FF_MAX_SS > FF_MIN_SS,FatFs被配置为扇区大小可变的并且必须在函数disk_ioctl中实现GET_SECTOR_SIZE命令。 512 根据实际硬件配置,如NAND Flash页大小为2K,则可以定义为2048
    FF_MAX_SS 512 根据实际硬件配置,强烈建议把FF_MIN_SS和FF_MAX_SS配置成相同的值
    FF_USE_TRIM 使能或禁用ATA-TRIM函数,0是禁用 0 0
    FF_FS_NOFSINFO 使能或禁用空闲簇计数和最后分配的簇计数,0是禁用 0 0
    FF_FS_TINY 配置FatFs为正常模式或者微型(TINY)模式。配置为微型模式后,对内存需求变小,文件对象数据结构FIL会减少_MAX_SS字节。程序复用FATFS数据结构中的缓冲区代替FIL数据结构中去除掉的缓冲区,0是正常模式 0 0
    FF_FS_EXFAT 使能或禁用exFAT文件系统,0是禁用 0 0
    FF_FS_NORTC 使能或禁用时间戳函数。使能时间戳函数需要硬件RTC,并且需要提供底层函数get_fattime 0 0
    FF_NORTC_MON 如果系统没有RTC,这些宏用来定义固定时间戳 1 1
    FF_NORTC_MDAY 1 1
    FF_NORTC_YEAR 2018 2018
    FF_FS_LOCK 使能或禁用文件锁功能,控制重复打开文件和非法打开文件对象,>0表示可同时打开的文件和文件夹数量 0 64
    FF_FS_REENTRANT 使能或禁用FatFs模块的可重入特性,0是禁用 0 1
    FF_FS_TIMEOUT 设置超时时间,单位为系统时钟滴答周期,当宏_FS_REENTRANT=0时,本设置无效 1000 1000
    FF_SYNC_t 定义同步对象类型,取决于OS,当宏FF_FS_REENTRANT=0时,本设置无效 HANDLE 根据实际平台配置

已配置功能:

  1. 支持全部基础接口
  2. 不支持字符处理接口
  3. 不支持搜索接口
  4. 支持f_mkfs接口
  5. 不支持多分区
  6. 支持长文件名(最长31字节)
  7. 支持同时打开在同一个分区上的多个文件
  8. 不支持exFAT

2.2. 资源需求
Fatfs本身并不需要其他的外设资源,只需要占用ROM和RAM。
下表是不同平台、不同配置,代码占用的空间统计:

其中Full表示支持全部接口,Min表示只支持最少的接口;R/W表示可支持文件系统的读写,R/O表示只读文件系统。
配置项中,文件名支持的编码也会影响代码大小,不同编码需要增加的代码空间如下所示:

以THM3100平台为例,使用Keil v5编译器,开启-O1优化选项,按照2.1节的自定义项进行配置,fatfs占用资源如下:
Code=9740 RO-data=1112 RW-data=8 ZI-data=1016
因此,FatFs需要ROM空间约11K字节,栈空间约1K字节。

2.3. 软件架构

整个软件框架如上图所示,应用程序只调用DDI接口,屏蔽底层不同文件系统的差异。FatFs内部也有分层,

  1. 对外是一系列的参考POSIX标准的API;
  2. 中间是文件系统的处理逻辑;
  3. 底下是disk IO API,这些API是由移植者实现,被FatFs调用,屏蔽不同存储设备的差异。

2.4. 关键数据结构

  1. 接口执行结果枚举
    typedef enum {
    FR_OK = 0, /* (0) Succeeded /
    FR_DISK_ERR, /
    (1) A hard error occurred in the low level disk I/O layer /
    FR_INT_ERR, /
    (2) Assertion failed /
    FR_NOT_READY, /
    (3) The physical drive cannot work /
    FR_NO_FILE, /
    (4) Could not find the file /
    FR_NO_PATH, /
    (5) Could not find the path /
    FR_INVALID_NAME, /
    (6) The path name format is invalid /
    FR_DENIED, /
    (7) Access denied due to prohibited access or directory full /
    FR_EXIST, /
    (8) Access denied due to prohibited access /
    FR_INVALID_OBJECT, /
    (9) The file/directory object is invalid /
    FR_WRITE_PROTECTED, /
    (10) The physical drive is write protected /
    FR_INVALID_DRIVE, /
    (11) The logical drive number is invalid /
    FR_NOT_ENABLED, /
    (12) The volume has no work area /
    FR_NO_FILESYSTEM, /
    (13) There is no valid FAT volume /
    FR_MKFS_ABORTED, /
    (14) The f_mkfs() aborted due to any problem /
    FR_TIMEOUT, /
    (15) Could not get a grant to access the volume within defined period /
    FR_LOCKED, /
    (16) The operation is rejected according to the file sharing policy /
    FR_NOT_ENOUGH_CORE, /
    (17) LFN working buffer could not be allocated /
    FR_TOO_MANY_OPEN_FILES, /
    (18) Number of open files > FF_FS_LOCK /
    FR_INVALID_PARAMETER /
    (19) Given parameter is invalid */
    } FRESULT;

  2. 文件句柄结构体
    typedef struct {
    FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) /
    BYTE flag; /
    File status flags /
    BYTE err; /
    Abort flag (error code) /
    FSIZE_t fptr; /
    File read/write pointer (Zeroed on file open) /
    DWORD clust; /
    Current cluster of fpter (invalid when fptr is 0) /
    DWORD sect; /
    Sector number appearing in buf[] (0:invalid) /
    #if !FF_FS_READONLY
    DWORD dir_sect; /
    Sector number containing the directory entry (not used at exFAT) /
    BYTE
    dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) /
    #endif
    #if FF_USE_FASTSEEK
    DWORD
    cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) /
    #endif
    #if !FF_FS_TINY
    BYTE buf[FF_MAX_SS]; /
    File private data read/write window */
    #endif
    } FIL;

2.5. 可调用接口
按照上述配置,FatFs可调用的接口如下:

  1. 打开文件
    FRESULT f_open (
    FIL* fp, /* [OUT] Pointer to the file object structure /
    const TCHAR
    path, /* [IN] File name /
    BYTE mode /
    [IN] Mode flags */
    );

  2. 关闭文件
    FRESULT f_close (
    FIL* fp /* [IN] Pointer to the file object */
    );

  3. 从文件读取内容
    FRESULT f_read (
    FIL* fp, /* [IN] File object /
    void
    buff, /* [OUT] Buffer to store read data /
    UINT btr, /
    [IN] Number of bytes to read /
    UINT
    br /* [OUT] Number of bytes read */
    );

  4. 把内容写入文件
    FRESULT f_write (
    FIL* fp, /* [IN] Pointer to the file object structure /
    const void
    buff, /* [IN] Pointer to the data to be written /
    UINT btw, /
    [IN] Number of bytes to write /
    UINT
    bw /* [OUT] Pointer to the variable to return number of bytes written */
    );

  5. 移动文件读写指针的位置
    FRESULT f_lseek (
    FIL* fp, /* [IN] File object /
    FSIZE_t ofs /
    [IN] File read/write pointer */
    );

  6. 截取文件大小
    FRESULT f_truncate (
    FIL* fp /* [IN] File object */
    );

  7. 把缓冲区的数据强制写入存储设备
    FRESULT f_sync (
    FIL* fp /* [IN] File object */
    );

  8. 获取当前读写指针的位置
    FSIZE_t f_tell (
    FIL* fp /* [IN] File object */
    );

  9. 获取文件大小
    FSIZE_t f_size (
    FIL* fp /* [IN] File object */
    );

  10. 打开文件夹
    FRESULT f_opendir (
    DIR* dp, /* [OUT] Pointer to the directory object structure /
    const TCHAR
    path /* [IN] Directory name */
    );

  11. 关闭文件夹
    FRESULT f_closedir (
    DIR* dp /* [IN] Pointer to the directory object */
    );

  12. 读取文件夹内容
    FRESULT f_readdir (
    DIR* dp, /* [IN] Directory object /
    FILINFO
    fno /* [OUT] File information structure */
    );

  13. 读取文件或子文件夹信息
    FRESULT f_stat (
    const TCHAR* path, /* [IN] Object name /
    FILINFO
    fno /* [OUT] FILINFO structure */
    );

  14. 删除文件或子文件夹
    FRESULT f_unlink (
    const TCHAR* path /* [IN] Object name */
    );

  15. 重命名文件或子文件夹
    FRESULT f_rename (
    const TCHAR* old_name, /* [IN] Old object name /
    const TCHAR
    new_name /* [IN] New object name */
    );

  16. 创建文件夹
    FRESULT f_mkdir (
    const TCHAR* path /* [IN] Directory name */
    );

  17. 挂载分区
    FRESULT f_mount (
    FATFS* fs, /* [IN] Filesystem object /
    const TCHAR
    path, /* [IN] Logical drive number /
    BYTE opt /
    [IN] Initialization option */
    );

  18. 创建分区
    FRESULT f_mkfs (
    const TCHAR* path, /* [IN] Logical drive number /
    BYTE opt, /
    [IN] Format options /
    DWORD au, /
    [IN] Size of the allocation unit /
    void
    work, /* [-] Working buffer /
    UINT len /
    [IN] Size of working buffer */
    );

  19. 获取指定分区空闲簇的数量
    FRESULT f_getfree (
    const TCHAR* path, /* [IN] Logical drive number /
    DWORD
    nclst, /* [OUT] Number of free clusters /
    FATFS
    * fatfs /* [OUT] Corresponding filesystem object */
    );

  20. 移植方法
    3.1. 存储设备操作接口
    FatFs把存储设备相关的操作接口都定义在diskio.c文件中,在移植时,需要实现5个接口,包括disk_status、disk_initialize、disk_read、disk_write和disk_ioctl。

  21. DSTATUS disk_initialize (BYTE pdrv);
    功能:根据传入参数,初始化指定的存储设备,并返回设备状态
    参数:pdrv存储设备ID
    返回值:正常返回0,错误值包括STA_NOINIT、STA_NODISK等状态。

  22. DSTATUS disk_status (BYTE pdrv);
    功能:根据传入参数,返回不同存储设备的状态
    参数:pdrv存储设备ID
    返回值:正常返回0,错误值包括STA_NOINIT、STA_NODISK等状态。

  23. DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
    功能:从存储设备读取一个扇区的数据,保存到buff。
    参数:sector表示从第几个扇区开始读取,从0开始,对应实际的偏移位置为sector * FF_MAX_SS。
    count表示读取几个扇区,实际读取的大小为count * FF_MAX_SS字节。
    返回值:函数执行成功返回RES_OK,错误值包括RES_ERROR、RES_NOTRDY等。

  24. DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
    功能:把buff中的数据写入到存储设备的指定位置。
    参数:sector表示从第几个扇区开始写入,从0开始,对应实际的偏移位置为sector * FF_MAX_SS。
    count表示读取几个扇区,实际读取的大小为count * FF_MAX_SS字节。
    返回值:函数执行成功返回RES_OK,错误值包括RES_ERROR、RES_NOTRDY等。

  25. DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
    功能:存储设备的控制命令。
    注意:需要根据配置实现不同的命令。

  1. CTRL_SYNC
    实现条件:FF_FS_READONLY == 0则必需实现此命令
    功能:阻塞写入缓冲区中的数据到存储器
    参数:无

  2. GET_SECTOR_COUNT
    实现条件:FF_USE_MKFS == 1则必需实现此命令
    功能:返回存储器的扇区总个数
    参数:(DWORD *)data,返回扇区个数

  3. GET_BLOCK_SIZE
    实现条件:FF_USE_MKFS == 1则必需实现此命令
    功能:返回一个擦除块共有几个扇区。这个命令主要是针对Flash存储器擦除时做数据对齐。返回的擦除块大小必需大于等于1且小于等于32768,并且只能是2的n次方。如果擦除块的大小未知或者是非Flash存储器,则返回1。
    参数:(DWORD *)data,返回一个擦除块的大小,单位扇区

3.2. 多线程互斥
配置FF_FS_REENTRANT = 1后,FatFs可以支持同时打开同一个存储器中的多个文件(线程安全)。FatFs总是支持同时打开保存在两个不同存储器的文件(线程安全),不受FF_FS_REENTRANT选项的影响。f_mount、f_mkfs和f_fdisk三个存储器控制函数总是不能同时操作,无论是否配置FF_FS_REENTRANT选项。
为了实现线程安全,移植时需要

  1. 配置FF_SYNC_t
    把FF_SYNC_t定义成当前平台互斥锁类型的指针,例如linux平台可定义为(pthread_mutex_t *)。

  2. 添加头文件
    把互斥锁类型的头文件包含在ffconf.h中,例如linux平台需要包含pthread.h头文件。

  3. 实现ffsystem.c中关于互斥的接口

  1. int ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj);
    功能:创建一个互斥锁
    参数:vol存储器编号
    sobj返回互斥锁句柄
    返回值:返回1表示成功,0表示失败

  2. int ff_req_grant (FF_SYNC_t sobj);
    功能:申请互斥锁
    参数:sobj互斥锁句柄
    返回值:返回1表示成功,0表示失败

  3. void ff_rel_grant (FF_SYNC_t sobj);
    功能:释放互斥锁
    参数:sobj互斥锁句柄

  4. int ff_del_syncobj (FF_SYNC_t sobj);
    功能:销毁一个互斥锁
    参数:sobj互斥锁句柄
    返回值:返回1表示成功,0表示失败

3.3. 文件名长度
默认支持的文件和文件夹名称长度为8字节。如果需要支持大于8字节长度的名称,需要配置FF_USE_LFN。
配置FF_USE_LFN 为非0值后,需要增加编译ffunicode.c文件。
配置FF_USE_LFN = 3后,需要实现ffsystem.c中的动态内存申请函数ff_memalloc和释放函数ff_memfree。

Fatfs配置与编译相关推荐

  1. uboot配置,编译,移植

    文章目录 前言 1.文件及文件夹 2.README文件 (1).配置及编译 (2).镜像格式 3.sd_fusing文件夹 4.主Makefile 总结 5.mkconfig 6.config.mk ...

  2. 编java用jdk还是editplus_怎样运用EditPlus进行配置Java编译环境

    不知道大家是否知道其实学习java主要有三种开发工具,分别是文本编辑软件.EcliPSe以及JBuilder.那么他们三者之间又有什么区别呢?小编就这三者发表一下个人的意见吧.对于学习Java的初学者 ...

  3. Cocos2d-x项目开发时在Eclipse中配置环境编译C++

    最近在做cocos2d-x的项目开发,当然前期肯定是环境的配置工作,为了能方便的在Eclipse中编辑和编译C++部分的代码,则需要配置Eclipse的环境,之前几次犯了一些错误,导致每次打开C++的 ...

  4. 【Android 插件化】VirtualAppEx 编译运行 ( VirtualAppEx 简介 | 配置 VirtualAppEx 编译环境 | 编译运行 VirtualAppEx 代码 )

    文章目录 一.VirtualAppEx 简介 二.配置 VirtualAppEx 编译环境 1.Android Studio 3.0 2.NDK 版本 ( Android NDK r10e ) 3.配 ...

  5. Star: Ubuntu下配置和编译cpp-ethereum客户端启动GPU加速交易

    Ubuntu下配置和编译cpp-ethereum客户端启动GPU加速交易 Ethereum,中文翻译是"以太坊",是一个公有区块链的开源项目.因为以太坊是基于P2P网络所以没有中心 ...

  6. Maven配置JDK编译版本

    配置JDK编译版本 配置使用JDK 1.8编译运行项目 打开Maven的settings.xml文件 在profiles节点中,加入如下配置 <profile><id>jdk- ...

  7. 深入理解Linux软件包的配置、编译与安装

    深入理解Linux软件包的配置.编译与安装   发布时间:2007.09.24 06:23     来源:赛迪网    作者:kit 从源代码安装过软件的朋友一定对 ./configure & ...

  8. linux-2.6.29内核配置、编译与安装

    Linux内核具有可定制的有点,下面讲述内核的配置和编译步骤 通常拿到一个内核系统源码,你不知道具体别人有没有配置过这个系统或做了哪些系统配置文件的修改,你要将系统还原到最初的默认配置状态,则直接进行 ...

  9. g++ linux 编译开栈_Linux下编写C++服务器(配置C++编译调试环境)

    Linux下编写C++服务器(配置C++编译调试环境) 安装好linux虚拟机,确定能上网后,我们可以开始编写C++程序了,但在这之前我们需要下载编译器和调试器 下载gcc 1.在终端输入yum se ...

最新文章

  1. 360浏览器、chrome开发扩展插件教程(2)为html添加行为
  2. 高性能udp服务器架构,优秀的国产高性能TCP/UDP/HTTP开源网络通信框架——HP
  3. JavaScript 易错知识点整理
  4. swi 指令能用在C语言吗,内嵌汇编指令的应用举例
  5. 特征工程之特征选择_特征工程与特征选择
  6. 有关性能测试结果的几点分析原则
  7. [密码学基础][每个信息安全博士生应该知道的52件事][Bristol Cryptography][第23篇]写一个实现蒙哥马利算法的C程序
  8. Linux——Linux下安装tree
  9. python分片上传_python 分片上传大格式
  10. 如何在MVC中下载模板和上传word文件
  11. 蓝桥杯省赛——杨辉三角java
  12. matlab盒子分形维数_根据计盒维数原理求一维曲线分形维数的matlab程序
  13. php 数据透视表,无法打开数据透视表源文件怎么解决
  14. IEEE Transactions on Mobile Computing -TMC
  15. SEO优化工具,查询死链VisualSEOStudio-2.0.2.3
  16. WPS之Excel表格如何设置下拉选项
  17. 蓝桥杯嵌入式基于STM32G4的模块总结【HAL库】【省赛】
  18. 004/160 CrackMe ajj CKme
  19. dspq值多少最好_抖音手机上怎么修改视频的md5值
  20. python可视化---阶梯图step()

热门文章

  1. ElasticSearch 从入门到入土
  2. 十五铬钼钢板和十二铬一钼钒钢板的区别
  3. Divide by 2 or 3
  4. OpenCV C++录制视频录制与播放
  5. PC与Android通过USB连接进行Socket通信
  6. 《特征工程三部曲》之一:数据处理
  7. VC++通过SetWindowHookEx去实时拦截窗口消息,实现视频会议中桌面共享图像的实时拖动(附源码)
  8. Apache服务器安装与配置详解
  9. 转载:中国部分酱香型白酒名录
  10. 百度2012年新进本科技术类员工培训教材ajax篇