FATFS简介

发布者:脑力风潮最新更新时间:2015-10-22 来源: eefocus关键字:FATFS  移植  文件系统 手机看文章 扫描二维码
随时随地手机看文章
一、概述

1、目的
在移植之前,先将源代码大概的阅读一遍,主要是了解文件系统的结构、各个函数的功能和接口、与移植

相关的代码等等。
2、准备工作
在官方网站下载了0.07c版本的源代码,利用记事本进行阅读。

二、源代码的结构
1、源代码组成
   源代码压缩包解压后,共两个文件夹,doc是说明,src里就是代码。src文件夹里共五个文件和一个文

件夹。文件夹是option,还有00readme.txt、diskio.c、diskio.h、ff.c、ff.h、integer.h。对比网上

的文章,版本已经不同了,已经没有所谓的tff.c和tff.h了,估计现在都采用条件编译解决这个问题了,

当然文件更少,可能编译选项可能越复杂。

2、00readme.txt的说明
  Low level disk I/O module is not included in this archive because the FatFs
  module is only a generic file system layer and not depend on any specific
  storage device. You have to provide a low level disk I/O module that written
  to control your storage device.主要是说不包含底层IO代码,这是个通用文件系统可以在各种介质

上使用。我们移植时针对具体存储设备提供底层代码。
  接下来做了版权声明-可以自由使用和传播。
  然后对版本的变迁做了说明。

3、源代码阅读次序
  先读integer.h,了解所用的数据类型,然后是ff.h,了解文件系统所用的数据结构和各种函数声明,然

后是diskio.h,了解与介质相关的数据结构和操作函数。再把ff.c和diskio.c两个文件所实现的函数大致

扫描一遍。最后根据用户应用层程序调用函数的次序仔细阅读相关代码。

三、源代码阅读
1、integer.h头文件
这个文件主要是类型声明。以下是部分代码。
typedef int    INT;
typedef unsigned int UINT;
typedef signed char  CHAR;
都是用typedef做类型定义。移植时可以修改这部分代码,特别是某些定义与你所在工程的类型定义有冲

突的时候。

2、ff.h头文件
以下是部分代码的分析
#include "integer.h" 使用integer.h的类型定义
#ifndef _FATFS
#define _FATFS 0x007C  版本号007c,0.07c
#define _WORD_ACCESS 0 //如果定义为1,则可以使用word访问。
中间有一些看着说明很容易弄清楚意思。这里就不例举了。

#define _CODE_PAGE 936

#define _FS_REENTRANT 0  //如果要支持文件系统可重入,必须加入几个函数。
#define _TIMEOUT  1000
#define _SYNC_t   HANDLE

#elif _CODE_PAGE == 936
#define _DF1S 0x81
#define _DF1E 0xFE
#define _DS1S 0x40
#define _DS1E 0x7E
#define _DS2S 0x80
#define _DS2E 0xFE
接下来很大一部分都是与语言相关的因素,略过。

三个宏判断是否大写、小写、数字。
#define IsUpper(c) (((c)>='A')&&((c)<='Z'))
#define IsLower(c) (((c)>='a')&&((c)<='z'))
#define IsDigit(c) (((c)>='0')&&((c)<='9'))

#if _DF1S     双字节编码相关的设定,暂时不理会它。

#if _MULTI_PARTITION        

//该变量定义为1时,支持一个磁盘的多个分区。

typedef struct _PARTITION {

       BYTE pd;    

       BYTE pt;     

} PARTITION;

Extern  const  PARTITION Drives[];//如果支持分区,则声明变量Drivers  

#define LD2PD(drv) (Drives[drv].pd)     

#define LD2PD(drv) (drv) 

#define LD2PT(drv) 0       

 

#if _MAX_SS == 512  //一般扇区长度取512字节。

#define   SS(fs)     512U

 

#if _LFN_UNICODE && _USE_LFN

typedef WCHAR XCHAR;       XCHAR是文件名的码型所用。

#else

typedef char XCHAR;       

#endif

 

typedef struct _FATFS_ {

       BYTE    fs_type;        

       BYTE    drive;            

       BYTE    csize;            

先查一下簇的含义:应该是文件数据分配的基本单位。

       BYTE    n_fats;          

FAT文件系统依次应该是:引导扇区、文件分配表两个、根目录区和数据区。

       BYTE    wflag;           

//文件是否改动的标志,为1时要回写。

       WORD  id;                

       WORD  n_rootdir;     

#if _FS_REENTRANT

       _SYNC_t     sobj;             

#endif

#if _MAX_SS != 512

       WORD  s_size;          

#endif

#if !_FS_READONLY  //文件为可写

       BYTE    fsi_flag;  

//文件需要回写的标志

       DWORD      last_clust;     

       DWORD      free_clust;     

       DWORD      fsi_sector;     

#endif

#if _FS_RPATH

       DWORD      cdir;             

//目前的扇区在win[]里面,这个win[]数组暂时还不知道含义。

       BYTE    win[_MAX_SS];

//这是一个win[512]数组,存储着一个扇区,好像作为扇区缓冲使用。

} FATFS;

 

typedef struct _DIR_ {

       FATFS* fs;指向相应文件系统对象。

       WORD  id;                

       WORD  index;     目前读写索引代码

       DWORD      sclust;     文件数据区开始簇

       DWORD      clust;             目前处理的簇

       DWORD      sect;              目前簇里对应的扇区

       BYTE*  dir; 

       BYTE*  fn;                

#if _USE_LFN

       WCHAR*     lfn;   指向长文件名缓冲。

       WORD  lfn_idx;  

#endif

} DIR;

 

typedef struct _FIL_ {

       FATFS* fs;                 

       WORD  id;                

       BYTE    flag;        文件状态标志

       BYTE    csect;            扇区偏移

       DWORD      fptr;        读写指针

       DWORD      fsize;             

       DWORD      org_clust;      文件开始簇

       DWORD      curr_clust;     当前簇

       DWORD      dsect;            文件当前扇区

#if !_FS_READONLY

       DWORD      dir_sect; 该文件目录项对应所在的扇区

       BYTE*  dir_ptr;  

#endif

#if !_FS_TINY

       BYTE    buf[_MAX_SS];文件读写缓冲

#endif

} FIL;

 

 

 

typedef struct _FILINFO_ {

       DWORD      fsize;             

       WORD  fdate;            

       WORD  ftime;            

       BYTE    fattrib;   

       char fname[13];    

#if _USE_LFN

       XCHAR*      lfname;         

       int   lfsize;            

#endif

} FILINFO; 这个结构主要描述文件的状态信息,包括文件名13个字符(8+.+3+)、属性、修改时间等。

接下来是函数的定义,先大概浏览一遍。

FRESULT f_mount (BYTE, FATFS*);    //加载文件系统,BYTE参数是ID,后一个是文件系统定义。

FRESULT f_open (FIL*, const XCHAR*, BYTE);//打开文件,第一个参数是文件信息结构,第二个参数是文件名,第三是文件打开模式

FRESULT f_read (FIL*, void*, UINT, UINT*);   //文件读取函数,参数1为文件对象(文件打开函数中得到),参数2为文件读取缓冲区,参数3为读取的字节数,参数4意义不清晰,等读到源代码就清楚了。

FRESULT f_write (FIL*, const void*, UINT, UINT*);//写文件,参数跟读差不多

FRESULT f_lseek (FIL*, DWORD); //移动文件的读写指针,参数2应该是移动的数目。

FRESULT f_close (FIL*);               

FRESULT f_opendir (DIR*, const XCHAR*);      打开目录,返回目录对象

FRESULT f_readdir (DIR*, FILINFO*);              读取目录,获得文件信息

FRESULT f_stat (const XCHAR*, FILINFO*);                       

FRESULT f_getfree (const XCHAR*, DWORD*, FATFS**);  

FRESULT f_truncate (FIL*);                  

FRESULT f_sync (FIL*);   将缓冲区数据写回文件

FRESULT f_unlink (const XCHAR*);            删除目录中的一个文件

FRESULT     f_mkdir (const XCHAR*);       

FRESULT f_chmod (const XCHAR*, BYTE, BYTE);

FRESULT f_utime (const XCHAR*, const FILINFO*);     

FRESULT f_rename (const XCHAR*, const XCHAR*);   

FRESULT f_forward (FIL*, UINT(*)(const BYTE*,UINT), UINT, UINT*); 这个函数还要提供一个回调函数。

FRESULT f_mkfs (BYTE, BYTE, WORD);         

FRESULT f_chdir (const XCHAR*);      改变当前目录

FRESULT f_chdrive (BYTE);          

应该说基本能明白这些函数用于干什么。

 [page]

#if _USE_STRFUNC

int f_putc (int, FIL*);                                                   

int f_puts (const char*, FIL*);                                      

int f_printf (FIL*, const char*, ...);                        

char* f_gets (char*, int, FIL*);                             

#define f_eof(fp) (((fp)->fptr == (fp)->fsize) ? 1 : 0)

#define f_error(fp) (((fp)->flag & FA__ERROR) ? 1 : 0)

 

#if _FS_REENTRANT  //如果定义了重入,则需要实现以下四个函数

BOOL ff_cre_syncobj(BYTE, _SYNC_t*); 创建同步对象

BOOL ff_del_syncobj(_SYNC_t);  删除同步对象

BOOL ff_req_grant(_SYNC_t);  申请同步对象

void ff_rel_grant(_SYNC_t); 释放同步对象。

#endif

3、diskio.h文件

typedef BYTE      DSTATUS;

typedef   DRESULT;  //首先定义了两个变量,各个函数都有用到。

 

BOOL assign_drives (int argc, char *argv[]); //这个函数不知道干吗

DSTATUS disk_initialize (BYTE); //磁盘初始化

DSTATUS disk_status (BYTE); //获取磁盘状态

DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);

#if   _READONLY == 0

DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);

#endif

DRESULT disk_ioctl (BYTE, BYTE, void*); //磁盘控制

接下来还有一些常数的定义,具体用到时在看。

 

4、diskio.c的结构

DSTATUS disk_initialize (   BYTE drv     )

{

       DSTATUS stat;

       int result;

       switch (drv) {

       case ATA :

              result = ATA_disk_initialize();

              // translate the reslut code here

              return stat;

       case MMC :

              result = MMC_disk_initialize();

              // translate the reslut code here

              return stat;

       case USB :

              result = USB_disk_initialize();

              // translate the reslut code here

              return stat;

       }

       return STA_NOINIT;

}

函数基本都像这样,drv表示磁盘的类型。没有实现,用户必须实现这部分代码。

 

5、ff.c文件简单浏览

#include "ff.h"                    

#include "diskio.h"             

#define   ENTER_FF(fs)           { if (!lock_fs(fs)) return FR_TIMEOUT; } //获取文件系统同步对象,不成功返回超时,成功,继续执行。

#define   LEAVE_FF(fs, res)     { unlock_fs(fs, res); return res; } //释放文件系统同步对象。

 

Static  FATFS *FatFs[_DRIVES]; //定义一个文件系统对象指针数组,当然一般我们也就用到一个元素。

Static WORD LfnBuf[_MAX_LFN + 1];  //这个是与长文件名支持相关的。

#define   NAMEBUF(sp,lp)      BYTE sp[12]; WCHAR *lp = LfnBuf

#define INITBUF(dj,sp,lp) dj.fn = sp; dj.lfn = lp

 

下面都是函数的定义,很多只在内部使用。

Static  void mem_cpy (void* dst, const void* src, int cnt) {

       char *d = (char*)dst;

       const char *s = (const char *)src;

       while (cnt--) *d++ = *s++;

} //接下来还定义了几个内存操作的函数,这个函数实现了从一块内存到另一块的复制,下面还有mem_set()对一块内存进行清0或设置操作;mem_cmp()比较内存的多个字节是否相同,相同返回0;chk_chr()检测字符串中是否存在某个字符,存在则返回该字符。

 

FRESULT move_window (

       FATFS *fs,          

       DWORD sector  

)//简单阅读了一下源代码,应该是改变文件系统的当前工作扇区,如果想要操作的扇区就是当前扇区,什么事不做;如果不是,则将原扇区写回;如果是FAT表,还得写入备份区。

这个函数内部使用,外部无法引用。

 

FRESULT sync ( 

       FATFS *fs    

)//这个函数用于更新FAT32文件系统的FSI_Sector。什么含义还不太清楚。

 

DWORD get_fat (      

       FATFS *fs,   

       DWORD clst      

)

       if (move_window(fs, fsect + (clst / (SS(fs) / 4)))) break; 获取簇号码对应的FAT扇区

       return LD_DWORD(&fs->win[((WORD)clst * 4) & (SS(fs) - 1)]) & 0x0FFFFFFF; //这个函数应该是获取簇的下一个连接簇。

综合起来,这个函数应该是获取下一簇,感觉这个函数名起得不太好。get_nextcluster感觉更好一点。

 

FRESULT put_fat (

       FATFS *fs,   

       DWORD clst,     

       DWORD val

)//上个函数是获取连接簇,这个是写入新的连接信息。

 

FRESULT remove_chain (

       FATFS *fs,                 

       DWORD clst                    

)//将下一簇号写为0,也就是该文件的簇到此为止,同时系统的自由簇增加1.

 

DWORD create_chain (    

       FATFS *fs,                 

       DWORD clst                    

)//跟上一个相反,在该簇的位置写入新的下一簇簇号。

DWORD clust2sect ( 

       FATFS *fs,          

       DWORD clst             

) //这个函数是将簇号转变为对应的扇区号。

clst * fs->csize + fs->database; //这个是算法

 

FRESULT dir_seek (

       DIR *dj,       

       WORD idx          

)//这个函数的最终目的是根据索引号找到目录项所在簇、所在扇区、并是目录对象的对象指针指向文件系统对象窗口扇区的对应位置。

 

FRESULT dir_next (  

       DIR *dj,       

       BOOL streach     

)//

 

FRESULT dir_read (

       DIR *dj               

)

 

FRESULT dir_register (     

       DIR *dj                      

)

 

FRESULT dir_remove (    

       DIR *dj                      

)

//以上这些函数都是对目录项的操作函数。

 

FRESULT create_name (

       DIR *dj,              

       const XCHAR **path  )

//这个函数太长了,具体用到的时候再说吧。

 

void get_fileinfo (        

       DIR *dj,              

       FILINFO *fno          )

该函数用于获取文件状态信息。主要是从文件的目录项中获取信息。

 

FRESULT follow_path (    

       DIR *dj,              

       const XCHAR *path  

)

该函数给定一个全路径,得到相应的目录对象。

 

BYTE check_fs ( 

       FATFS *fs,   

       DWORD sect      )

该函数用于读取BOOT扇区,检查是否FAT文件系统。

 

FRESULT auto_mount (    

       const XCHAR **path,      

       FATFS **rfs,             

       BYTE chk_wp                   )

这个函数的功能不太明白。

 

FRESULT validate (   

       FATFS *fs,          

       WORD id                  

)//检查是否合法的文件系统。

 

FRESULT f_mount (

       BYTE vol,           

       FATFS *fs            )

这是一个很重要的函数,装载文件系统。也是从这个函数开始,对外输出供用户调用。

if (vol >= _DRIVES)现在只支持卷号0.

FatFs[vol] = fs;将参数文件系统对象指针赋给全局文件对象指针。

 

后面的函数主要是对文件和目录进行操作,这里就不一一例举了。

关键字:FATFS  移植  文件系统 引用地址:FATFS简介

上一篇:TQ2440复制文件无法编译问题
下一篇:STM32启动代码分析

推荐阅读最新更新时间:2024-03-16 14:36

Linux-2.6.32.2内核在mini2440上的移植(六)---添加LCD背光驱动
移植环境 1,主机环境:VMare下CentOS 5.5 ,1G内存。 2,集成开发环境:Elipse IDE 3,编译编译环境:arm-linux-gcc v4.4.3,arm-none-linux-gnueabi-gcc v4.5.1。 4,开发板:mini2440,2M nor flash,128M nand flash。 5,u-boot版本:u-boot-2009.08 6,linux 版本:linux-2.6.32.2 7,参考文章: 嵌入式linux应用开发完全手册,韦东山,编著。 Mini2440 之Linux 移植开发实战指南 到目前为止,我们一直都在命令行下移植,查看结果,LCD 屏幕上似乎总是如伸手不见五指
[单片机]
Linux-2.6.32.2内核在mini2440上的<font color='red'>移植</font>(六)---添加LCD背光驱动
移植嵌入式Linux到ARM处理器S3C2410:BootLoader
BootLoader指系统启动后,在操作系统内核运行之前运行的一段小程序。通过BootLoader,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。通常,BootLoader是严重地依赖于硬件而实现的,特别是在嵌入式世界。因此,在嵌入式世界里建立一个通用的 BootLoader 几乎是不可能的。尽管如此,我们仍然可以对BootLoader归纳出一些通用的概念来,以指导用户特定的BootLoader设计与实现。   BootLoader 的实现依赖于CPU的体系结构,因此大多数 BootLoader 都分为stage1 和stage2 两大部分。依赖
[单片机]
<font color='red'>移植</font>嵌入式Linux到ARM处理器S3C2410:BootLoader
TQ210学习之路(1)——移植软件
编译之前,先安装交叉编译工具。只需把编译工具的路径写到环境变量PATH里即可。 软件移植: 1,官网下载源代码并放到开发环境里。 2,解压。如tar zxvf xxx.tar.gz 3,生成Makefile。大部分情况下,软件包里都会包含configure这个脚本。可以直接执行 ./configure --host=xxx --prefix=xxx来进行配置生成Makefile。 说明:host表示目标主机架构,prefix表示软件安装路径。 4,从安装路径里选择需要的部分传输到嵌入式板文件系统的相应位置如/usr里面,一般需要的东西有 可执行文件/bin和/sbin,动态库/lib里的东西。
[单片机]
八代酷睿完美移植100/200系主板
受到对手刺激,Intel 2017年终于结束了多年的“挤牙膏”历史,各条产品线全面提速,但却玩起了不兼容。 八代酷睿桌面版Coffee Lake-S全线增加了核心数量,而在接口保持LGA1151完全不变的情况下,Intel以电气特性变化导致不兼容为由,强迫新处理器必须搭配几乎毫无变化的300系列芯片组,而且首发只有昂贵的Z370,将好好的100/200系列主板抛之脑后。 不过华硕曾经忍不住披露,八代酷睿原本是兼容100/200系主板的,但是Intel最后关头改变了主意。 更是有多位国内玩家通过试验证明,八代酷睿确实可以在老主板上点亮,但仅在极少数型号上实现,稳定性也不好。 现在,来自国外硬件论坛Overclock.net的几位
[嵌入式]
ARM+llinux系统移植3G拨号上网收发短信(二)
一、发送text格式的短信 给联通发text格式的短信: ~ : microcom -s 115200 /dev/ttyUSB1 at OK 设置短信格式为Text模式: at+cmgf=1 OK at+cmgs= +861300711**** 输入发送的内容: hello (内容写完后按一下ctrl + z发送) +CMGS: 48 OK 给电信发text格式的短信: ~ : microcom -s 115200 /dev/ttyUSB1 at OK 设置短信格式为Text模式: at+cmgf=1 OK at+cmgs= +861532736**** 设
[单片机]
ARM+llinux系统<font color='red'>移植</font>3G拨号上网收发短信(二)
3D生物打印取得重大突破,有望造出用于移植的人造器官
    据国外媒体报道,科学家宣称在3D器官打印方面取得巨大突破,在需要的时候能够在医院打印器官。     一个国际团队日前制造出器官内部供血的整个血管网络。     科学家说该技术甚至能对癌症损伤的器官进行简单替换。     悉尼、哈佛、斯坦福大学和麻省理工学院的研究人员现在已经利用生物打印技术制造出人工的血管网络,能模拟人体的循环系统为制造大的复杂组织提供必要条件。     研究的领导者,悉尼大学的Luiz Bertassoni教授说,每年因为缺乏移植器官会造成很多人死亡。很多人也会因为癌症或意外事故而切除组织和器官。想象一下,当你走进医院,当你按下打印按钮后,准备好的细胞、蛋白质和精确位置下的血管就能打印出完整的器
[医疗电子]
移植ucosII到STM32F103ZE(一)
一、开发环境: 1. 开发环境: keil uvision4 MDK4.12(windows XP) MDK即RealView MDK(Microcontroller Development kit),是 ARM 公司目前最新推出的针对各种嵌入式处理器的软件开发工具。RealView MDK 集成了业内最领先的技术,包括 uVision4 集成开发环境与 RealView 编译器。支持 ARM7、ARM9 和最新的 Cortex-M3/M1/M0 核处理器,自动配置启动代码,集成 Flash 烧写模块,强大的 Simulation 设备模拟,性能分析等功能,与 ARM 之前的工具包 ADS 等相比,RealV
[单片机]
在C51系统上实现YAFFS文件系统
随着NAND Flash存储器作为大容量数据存储介质的普及,基于NAND闪存的文件系统YAFFS(Yet Another Flash File System)正逐渐被应用到各种嵌入式系统中。本文将详细阐述YAFFS文件系统在C51系统上的实现过程。 1 NAND Flash的特点 非易失性闪速存储器Flash具有速度快、成本低、密度大的特点,被广泛应用于嵌入式系统中。Flash存储器主要有NOR和NAND两种类型。NOR型比较适合存储程序代码;NAND型则可用作大容量数据存储。NAND闪存的存储单元为块和页。本文使用的Samsung公司的K9F5608包括2 048块,每一块又包括32页,一页大小为528字节,依次分为2个256
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved