[STM32]-stm32+sdio+fatfs文件系统-源码分析_第1页
[STM32]-stm32+sdio+fatfs文件系统-源码分析_第2页
[STM32]-stm32+sdio+fatfs文件系统-源码分析_第3页
[STM32]-stm32+sdio+fatfs文件系统-源码分析_第4页
[STM32]-stm32+sdio+fatfs文件系统-源码分析_第5页
已阅读5页,还剩12页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、STM32 stm32+sdio+fatfs文件系统 源码分析一、概述1、目的在移植之前,先将源代码大概的阅读一遍,主要是了解文件系统的结构、各个函数的功能和接口、与移植相关的代码等等。2、准备工作在官方网站下载了0.07c版本的源代码,利用记事本进行阅读。二、源代码的结构1、源代码组成   源代码压缩包解压后,共两个文件夹,doc是说明,src里就是代码。src文件夹里共五个文件和一个文件夹。文件夹是option,还有00readme.txt、diskio.c、diskio.h、ff.c、ff.h、integer.h。对比网上的文章,版本已经不同了,已经没有所谓的tff.

2、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

3、written to control your storage device.主要是说不包含底层IO代码,这是个通用文件系统可以在各种介质上使用。我们移植时针对具体存储设备提供底层代码。  接下来做了版权声明-可以自由使用和传播。然后对版本的变迁做了说明。3、源代码阅读次序  先读integer.h,了解所用的数据类型,然后是ff.h,了解文件系统所用的数据结构和各种函数声明,然后是diskio.h,了解与介质相关的数据结构和操作函数。再把ff.c和diskio.c两个文件所实现的函数大致扫描一遍。最后根据用户应用层程序调用函数的次序仔细阅读相关代码。三

4、、源代码阅读1、integer.h头文件这个文件主要是类型声明。以下是部分代码。typedef int    INT;typedef unsigned int UINT;typedef signed char  CHAR;/* These types must be 8-bit integer */都是用typedef做类型定义。移植时可以修改这部分代码,特别是某些定义与你所在工程的类型定义有冲突的时候。2、ff.h头文件以下是部分代码的分析#include "integer.h" 使用integer.h的类型定义#ifndef _F

5、ATFS#define _FATFS 0x007C  版本号007c,0.07c#define _WORD_ACCESS 0 /如果定义为1,则可以使用word访问。中间有一些看着说明很容易弄清楚意思。这里就不例举了。#define _CODE_PAGE 936/* The _CODE_PAGE specifies the OEM code page to be used on the target system.OEM code page什么意思不大明白。/   936  - Simplified Chinese GBK (DBCS

6、, OEM, Windows)跟据这个中国应该是936.打开option文件夹看一下。打开cc936.c文件,里面有一个很大的数组static const WCHAR uni2oem 。根据英文说明,这个数组用于unicode码和OEM码之间的相互转换。接下来又有两个函数ff_convert()和ff_wtoupper()具体执行码型转换和将字符转换为大写。百度一下:看OEM码什么意思。unicode是一种双字节字符编码,无论中文还是英文,或者其他语言统一到2个字节。与现有的任何编码(ASCII,GB等)都不兼容。WindowsNT(2000)的内核即使用该编码,所有数据进入内核前转换成UNI

7、CODE,退出内核后在转换成版本相关的编码(通常称为OEM,在简体中文版下即为GB).(百度所得)继续往下阅读。#define _USE_LFN 1   /这个估计是长文件名支持了,以前的0.06版本好像是不支持。#define _MAX_LFN 255 /最长支持255个双字节字符。#define _FS_RPATH 0  /是否文件相对路径选项。/* When _FS_RPATH is set to 1, relative path feature is enabled and f_chdir,/  f_chdrive funct

8、ion are available.  /有些函数会受影响。/  Note that output of the f_readdir fnction is affected by this option. */#define _FS_REENTRANT 0  /如果要支持文件系统可重入,必须加入几个函数。#define _TIMEOUT  1000 /* Timeout period in unit of time ticks of the OS */#define _SYNC_t   HAND

9、LE /* Type of sync object used on the OS. e.g. HANDLE,OS_EVENT*, ID and etc. */* To make the FatFs module re-entrant, set _FS_REENTRANT to 1 and add user/  provided synchronization handlers, ff_req_grant, ff_rel_grant, ff_del_syncobj/  and ff_cre_syncobj function to the project.

10、*/#elif _CODE_PAGE = 936 /* Simplified Chinese GBK */#define _DF1S 0x81#define _DF1E 0xFE#define _DS1S 0x40#define _DS1E 0x7E#define _DS2S 0x80#define _DS2E 0xFE接下来很大一部分都是与语言相关的因素,略过。/* Character code support macros */ 三个宏判断是否大写、小写、数字。#define IsUpper(c) (c)>='A')&&(c)<='Z&#

11、39;)#define IsLower(c) (c)>='a')&&(c)<='z')#define IsDigit(c) (c)>='0')&&(c)<='9')#if _DF1S     /* DBCS configuration */双字节编码相关的设定,暂时不理会它。#if _MULTI_PARTITION         /* Multiple partition c

12、onfiguration */该变量定义为1时,支持一个磁盘的多个分区。typedef struct _PARTITION        BYTE pd;     /* Physical drive# */       BYTE pt;      /* Partition # (0-3) */ PARTITION;Extern  const  PARTITION Drives;/如果支持分区,则声

13、明变量Drivers   #define LD2PD(drv) (Drivesdrv.pd)      /* 获得磁盘对应的物理磁盘#define LD2PT(drv) (Drivesdrv.pt)       /*获得磁盘对应的分区#else                             

14、0;           /* Single partition configuration */#define LD2PD(drv) (drv)  /* Physical drive# is equal to the logical drive# */#define LD2PT(drv) 0        /* Always mounts the 1st partition */#if _MAX_SS = 512  

15、;/一般扇区长度取512字节。#define   SS(fs)     512U#if _LFN_UNICODE && _USE_LFNtypedef WCHAR XCHAR;       /* Unicode */ XCHAR是文件名的码型所用。#elsetypedef char XCHAR;        /* SBCS, DBCS */#endiftypedef struct _FATFS_   

16、0;    BYTE    fs_type;         /* FAT sub type */       BYTE    drive;             /*对应实际驱动号01- */       BYTE    csize;       

17、;      /* 每个簇的扇区数目 */先查一下簇的含义:应该是文件数据分配的基本单位。       BYTE    n_fats;           /* 文件分配表的数目 */FAT文件系统依次应该是:引导扇区、文件分配表两个、根目录区和数据区。       BYTE    wflag;        

18、0;   /* win dirty flag (1:must be written back) */文件是否改动的标志,为1时要回写。       WORD  id;                 /* File system mount ID 文件系统加载ID*/       WORD  n_rootdir;   

19、   /* 根目录区目录项的数目 */#if _FS_REENTRANT       _SYNC_t     sobj;              /* 允许重入,则定义同步对象 */#endif#if _MAX_SS != 512       WORD  s_size;        &

20、#160;  /* Sector size */#endif#if !_FS_READONLY  /文件为可写       BYTE    fsi_flag;   /* fsinfo dirty flag (1:must be written back) */文件需要回写的标志       DWORD      last_clust;      /* Las

21、t allocated cluster */       DWORD      free_clust;      /* Number of free clusters */       DWORD      fsi_sector;      /* fsinfo sector */#endif#if _FS_RPATH     &

22、#160; DWORD      cdir;              /* 使用相对路径,则要存储文件系统当前目录#endif       DWORD      sects_fat;       /*文件分配表占用的扇区       DWORD      m

23、ax_clust;     /* 最大簇数       DWORD      fatbase;  /*文件分配表开始扇区       DWORD      dirbase;  /*  如果是FAT32,根目录开始扇区需要首先得到。       DWORD     

24、60;database;       /* 数据区开始扇区       DWORD      winsect;  /* Current sector appearing in the win */目前的扇区在win里面,这个win数组暂时还不知道含义。       BYTE    win_MAX_SS;/* Disk access window for Directory/FAT */这是一个wi

25、n512数组,存储着一个扇区,好像作为扇区缓冲使用。 FATFS;typedef struct _DIR_        FATFS* fs;/* Pointer to the owner file system object */指向相应文件系统对象。       WORD  id;                 /* 文件系统加载ID*/   

26、0;   WORD  index;     /* Current read/write index number */目前读写索引代码       DWORD      sclust;     /* Table start cluster (0:Static table) */文件数据区开始簇       DWORD      

27、clust;             /* Current cluster */ 目前处理的簇       DWORD      sect;              /* Current sector */ 目前簇里对应的扇区       BYTE*  dir; &#

28、160;/* Pointer to the current SFN entry in the win */       BYTE*  fn;                 /* Pointer to the SFN (in/out) file8,ext3,status1 */#if _USE_LFN       WCHAR*     l

29、fn;   /* Pointer to the LFN working buffer */ 指向长文件名缓冲。       WORD  lfn_idx;   /* Last matched LFN index number (0xFFFF:No LFN) */#endif DIR;typedef struct _FIL_        FATFS* fs;            

30、;      /* Pointer to the owner file system object */       WORD  id;                 /* Owner file system mount ID */       BYTE    flag;     

31、60;  /* File status flags */文件状态标志       BYTE    csect;            /* Sector address in the cluster */扇区偏移       DWORD      fptr;        /* File R/W p

32、ointer */ 读写指针       DWORD      fsize;              /* File size */       DWORD      org_clust;      /* File start cluster */文件开始簇    

33、  DWORD      curr_clust;     /* Current cluster */当前簇       DWORD      dsect;            /* Current data sector */文件当前扇区#if !_FS_READONLY       DWORD 

34、     dir_sect; /* Sector containing the directory entry */该文件目录项对应所在的扇区       BYTE*  dir_ptr;   /* Ponter to the directory entry in the window */#endif#if !_FS_TINY       BYTE    buf_MAX_SS;/* File R/W buffer */文件读写

35、缓冲#endif FIL;/* File status structure */typedef struct _FILINFO_        DWORD      fsize;              /* File size */       WORD  fdate;         

36、0;   /* Last modified date */       WORD  ftime;             /* Last modified time */       BYTE    fattrib;    /* Attribute */       char fname13;    

37、; /* Short file name (8.3 format) */#if _USE_LFN       XCHAR*      lfname;          /* Pointer to the LFN buffer */       int   lfsize;             /* Size

38、 of LFN buffer chrs */#endif FILINFO; 这个结构主要描述文件的状态信息,包括文件名13个字符(8+.+3+0)、属性、修改时间等。接下来是函数的定义,先大概浏览一遍。FRESULT f_mount (BYTE, FATFS*);    /加载文件系统,BYTE参数是ID,后一个是文件系统定义。FRESULT f_open (FIL*, const XCHAR*, BYTE);/打开文件,第一个参数是文件信息结构,第二个参数是文件名,第三是文件打开模式FRESULT f_read (FIL*, void*, UINT, UINT*);

39、60;  /文件读取函数,参数1为文件对象(文件打开函数中得到),参数2为文件读取缓冲区,参数3为读取的字节数,参数4意义不清晰,等读到源代码就清楚了。FRESULT f_write (FIL*, const void*, UINT, UINT*);/写文件,参数跟读差不多FRESULT f_lseek (FIL*, DWORD); /移动文件的读写指针,参数2应该是移动的数目。FRESULT f_close (FIL*);                /* Close an ope

40、n file object */FRESULT f_opendir (DIR*, const XCHAR*);      打开目录,返回目录对象FRESULT f_readdir (DIR*, FILINFO*);              读取目录,获得文件信息FRESULT f_stat (const XCHAR*, FILINFO*);             

41、           /* Get file status */FRESULT f_getfree (const XCHAR*, DWORD*, FATFS*);   /* Get number of free clusters on the drive */FRESULT f_truncate (FIL*);                   /* Truncate file */F

42、RESULT f_sync (FIL*);   /* Flush cached data of a writing file */将缓冲区数据写回文件FRESULT f_unlink (const XCHAR*);            删除目录中的一个文件FRESULT     f_mkdir (const XCHAR*);        /* Create a new directory */

43、FRESULT f_chmod (const XCHAR*, BYTE, BYTE); /* Change attriburte of the file/dir */FRESULT f_utime (const XCHAR*, const FILINFO*);      /* Change timestamp of the file/dir */FRESULT f_rename (const XCHAR*, const XCHAR*);    /* Rename/Move a file or directory */FRESULT f

44、_forward (FIL*, UINT(*)(const BYTE*,UINT), UINT, UINT*); /* Forward data to the stream */ 这个函数还要提供一个回调函数。FRESULT f_mkfs (BYTE, BYTE, WORD);          /* Create a file system on the drive */FRESULT f_chdir (const XCHAR*);      /* Change current directo

45、ry */改变当前目录FRESULT f_chdrive (BYTE);           /* Change current drive */应该说基本能明白这些函数用于干什么。#if _USE_STRFUNCint f_putc (int, FIL*);                              

46、                      /* Put a character to the file */int f_puts (const char*, FIL*);                                 &

47、#160;     /* Put a string to the file */int f_printf (FIL*, const char*, .);                         /* Put a formatted string to the file */char* f_gets (char*, int, FIL*);       

48、                       /* Get a string from the file */#define f_eof(fp) (fp)->fptr = (fp)->fsize) ? 1 : 0)#define f_error(fp) (fp)->flag & FA_ERROR) ? 1 : 0)#if _FS_REENTRANT  /如果定义了重入,则需要实现以下四个函数BOOL

49、ff_cre_syncobj(BYTE, _SYNC_t*); 创建同步对象BOOL ff_del_syncobj(_SYNC_t);  删除同步对象BOOL ff_req_grant(_SYNC_t);  申请同步对象void ff_rel_grant(_SYNC_t); 释放同步对象。#endif3、diskio.h文件typedef BYTE      DSTATUS;typedef   DRESULT;  /首先定义了两个变量,各个函数都有用到。BOOL assign

50、_drives (int argc, char *argv); /这个函数不知道干吗DSTATUS disk_initialize (BYTE); /磁盘初始化DSTATUS disk_status (BYTE); /获取磁盘状态DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);#if   _READONLY = 0DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);#endifDRESULT disk_ioctl (BYTE, BYTE, void*); /磁盘控制接下来还有一些常

51、数的定义,具体用到时在看。4、diskio.c的结构DSTATUS disk_initialize (   BYTE drv     /* Physical drive nmuber (0.) */)       DSTATUS stat;       int result;       switch (drv)        case ATA :   &#

52、160;          result = ATA_disk_initialize();              / translate the reslut code here              return stat;       case MMC :  

53、0;           result = MMC_disk_initialize();              / translate the reslut code here              return stat;       case USB : 

54、            result = USB_disk_initialize();              / translate the reslut code here              return stat;          

55、    return STA_NOINIT;函数基本都像这样,drv表示磁盘的类型。没有实现,用户必须实现这部分代码。5、ff.c文件简单浏览#include "ff.h"                     /* FatFs configurations and declarations */#include "diskio.h"       

56、;       /* Declarations of low level disk I/O functions */#define   ENTER_FF(fs)            if (!lock_fs(fs) return FR_TIMEOUT; /获取文件系统同步对象,不成功返回超时,成功,继续执行。#define   LEAVE_FF(fs, res)      unlock

57、_fs(fs, res); return res; /释放文件系统同步对象。Static  FATFS *FatFs_DRIVES; /定义一个文件系统对象指针数组,当然一般我们也就用到一个元素。Static WORD LfnBuf_MAX_LFN + 1;  /这个是与长文件名支持相关的。#define   NAMEBUF(sp,lp)      BYTE sp12; WCHAR *lp = LfnBuf#define INITBUF(dj,sp,lp) dj.fn = sp; dj.lfn

58、= 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_se

59、t()对一块内存进行清0或设置操作;mem_cmp()比较内存的多个字节是否相同,相同返回0;chk_chr()检测字符串中是否存在某个字符,存在则返回该字符。FRESULT move_window (       FATFS *fs,           /* File system object */       DWORD sector   /* Sector number to make apperance

60、in the fs->win */)/简单阅读了一下源代码,应该是改变文件系统的当前工作扇区,如果想要操作的扇区就是当前扇区,什么事不做;如果不是,则将原扇区写回;如果是FAT表,还得写入备份区。这个函数内部使用,外部无法引用。FRESULT sync (  /* FR_OK: successful, FR_DISK_ERR: failed */       FATFS *fs     /* File system object */)/这个函数用于更新FAT32文件系统的FSI_Sect

61、or。什么含义还不太清楚。DWORD get_fat (       /* 0xFFFFFFFF:Disk error, 1:Interal error, Else:Cluster status */       FATFS *fs,    /* File system object */       DWORD clst       /* Cluster# to get the link information *

62、/)       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 (&#

63、160;      FATFS *fs,    /* File system object */       DWORD clst,      /* Cluster# to be changed in range of 2 to fs->max_clust - 1 */       DWORD val /* New value to mark the cluster */)/上个函数是获取连接簇,这个是写入新的连接信息。

64、FRESULT remove_chain (       FATFS *fs,                  /* File system object */       DWORD clst                     /* Cluster#

65、 to remove a chain from */)/将下一簇号写为0,也就是该文件的簇到此为止,同时系统的自由簇增加1.DWORD create_chain (     /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */       FATFS *fs,                

66、  /* File system object */       DWORD clst                     /* Cluster# to stretch. 0 means create a new chain. */)/跟上一个相反,在该簇的位置写入新的下一簇簇号。DWORD clust2sect (  /* !=0: Sector number, 0: Failed

67、 - invalid cluster# */       FATFS *fs,           /* File system object */       DWORD clst              /* Cluster# to be converted */) /这个函数是将簇号转变为对应的扇区号。clst * fs->

68、csize + fs->database; /这个是算法FRESULT dir_seek (       DIR *dj,        /* Pointer to directory object */       WORD idx           /* Directory index number */)/这个函数的最终目的是根据索引号找到目录项所在簇、所在扇区、

69、并是目录对象的对象指针指向文件系统对象窗口扇区的对应位置。FRESULT dir_next (   /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:EOT and could not streach */       DIR *dj,        /* Pointer to directory object */       BOOL streach   

70、;   /* FALSE: Do not streach table, TRUE: Streach table if needed /) /移动当前目录项,根据索引,源代码简单看了一下,作用还不是很清晰,先放过。接下来有5个函数与长文件名有关,这里先跳过。FRESULT dir_find (       DIR *dj                /* Pointer to the directory object linked to

71、 the file name */)/FRESULT dir_read (       DIR *dj                /* Pointer to the directory object that pointing the entry to be read */)FRESULT dir_register (      /* FR_OK:Successful, FR_DENIED:No free ent

72、ry or too many SFN collision, FR_DISK_ERR:Disk error */       DIR *dj                       /* Target directory with object name to be created */)FRESULT dir_remove (     /* FR_OK:

73、 Successful, FR_DISK_ERR: A disk error */       DIR *dj                       /* Directory object pointing the entry to be removed */)/以上这些函数都是对目录项的操作函数。FRESULT create_name (       DIR *dj,               /* Pointer to the directory object */       const XCHAR *path  /* Pointer to pointer to the segment in the path string */)/这个函数太长了,具体用到的时候再说吧。void get_fileinfo (

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论