原创 FatFS执行流程分析(一)

2009-11-19 20:47 6546 7 7 分类: MCU/ 嵌入式

<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 


在网上找了一个FatFS移植的例子,并含有源代码。


http://blog.ednchina.com/jjldc/190753/message.aspx


在主程序中,有FatFS操作的流程,我的流程分析就以这个为基础。


 


一、读文件流程。


1、程序结构


   res = f_mount(0, &fs);    


res = f_open(&file, "data.txt", FA_OPEN_EXISTING | FA_READ);


   while(1)


    {   if(fgets(data, sizeof(data), &file)==NULL)


        {    break;    }


        prints(data);


    }


   f_close(&file);


总共四个与文件系统相关的函数,下面就沿着函数执行路径去探索一下。


 


2f_mount(0, &fs)的执行


   参数0是卷号,就像电脑上的CDE盘等。fs是一个未初始化的一个文件系统对象,其定义在此:FATFS fs。这个函数好像就做了两个个事,使全局文件系统指针FatFS指向fs对象,并使fs.fstype=0


 


3f_open(&file, "data.txt", FA_OPEN_EXISTING | FA_READ)的执行


参数&file是提供一个文件对象指针,打开文件过程中获得的一些信息都填入这个结构体。FA_OPEN_EXISTING | FA_READ表示要打开和读取相应的文件。源程序如下:


FRESULT f_open (


       FIL *fp,                /* fp就指向传入的对象file */


       const char *path,    /*path指向data.txt的地址 */


       BYTE mode                /* Access mode and file open mode flags */


)


{


       DIR dj; 目录对象


       BYTE *dir; 目录项指针


       char fn[8+3+1]; 8.3文件名。  // 程序开头定义了这么三个变量,<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />007c版本中由于支持长文件名,最好一个改为NAMEBUF(sfn, lfn)


fp->fs = NULL;          每个文件对象都指向具体的文件系统,这里先清0


   auto_mount(&path, &dj.fs, (BYTE)(mode) ); //这个函数看来很关键了。旧版的函数没有中间这个参数。


Path本来就是一个指针,&path就是一个指向指针的指针,&dj.fs因为dj对象还未设置,这个指针传入应该是供auto_mount函数设置的。


 


4auto_mount(&path, &dj.fs, (BYTE)(mode) )的执行


先分析旧版的:


FRESULT auto_mount (     /* FR_OK(0): successful, !=0: any error occured */


       const char **path,       /* Pointer to pointer to the path name (drive number) */


       BYTE chk_wp            /* !=0: Check media write protection for write access)


{


       DWORD bootsect, fatsize, totalsect, maxclust;


       const char *p = *path;  //指针p现在就指向文件名字符串了。


       FATFS *fs;


 


       memset(fs, 0, sizeof(FATFS));           /*将全局文件系统结构清0 */


       stat = disk_initialize(0);       /*磁盘初始化程序,在这里调用的 */


 


       fmt = check_fs(bootsect = 0);           /* Check sector 0 as an SFD format */


这里主要是调用了check_fs(bootsect = 0)函数检测是否存在FAT文件系统。


 


下面是源代码:


BYTE check_fs (  /* 0:The FAT boot record, 1:Valid boot record but not an FAT, 2:Not a boot record or error */


       DWORD sect      /* Sector# to check if it is an FAT boot record or not */


)


{     FATFS *fs = FatFs;


       if (disk_read(0, fs->win, sect, 1) != RES_OK)      /* Load boot record */


              return 2; 


       if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55)     /*Check record signature */


              return 2;


       if (!memcmp(&fs->win[BS_FilSysType], "FAT", 3))/* Check FAT signature */


              return 0;


       if (!memcmp(&fs->win[BS_FilSysType32], "FAT32", 5) && !(fs->win[BPB_ExtFlags] & 0x80))


              return 0;


       return 1;}


这个函数的主要操作是:将磁盘的0扇区读入fs->win【】扇区缓冲。并对其中的特殊位置进行检验。如果读入错误或者末尾不是55AA,返回2。如果确实是FAT文件系统返回0。如果返回1可能是主引导扇区,继续从分区引导扇区读取。


 


auto_mount继续往下执行:


       fatsize = LD_DWORD(&fs->win[BPB_FATSz32]);


       fs->sects_fat = (CLUST)fatsize;  //每个FAT表的扇区数目


       fs->n_fats = fs->win[BPB_NumFATs];           /* FAT表的个数 */


       fatsize *= fs->n_fats;                                      /* (Number of sectors in FAT area) */


       fs->fatbase = bootsect + LD_WORD(&fs->win[BPB_RsvdSecCnt]);      /* FAT start sector (lba) */FAT表开始于开始扇区+保留扇区。


       fs->csize = fs->win[BPB_SecPerClus];          /* 每个簇的扇区数目 */


       fs->n_rootdir = LD_WORD(&fs->win[BPB_RootEntCnt]);       /* Nmuber of root directory entries */


       totalsect = LD_DWORD(&fs->win[BPB_TotSec32]); 


       fs->max_clust = maxclust;


       fmt = FS_FAT32;


       if (fmt == FS_FAT32)


       fs->dirbase = LD_DWORD(&fs->win[BPB_RootClus]);   


       fs->database = fs->fatbase + fatsize + fs->n_rootdir / 16;    /* Data start sector (lba)


       fs->free_clust = (CLUST)0xFFFFFFFF;


//以上代码主要是根据引导扇区里的数据,填充文件系统对象结构体的信息:包括FAT表大小、数目、根目录区起始地址、数据区起始扇区、文件系统类型等等。后面还有一些代码,也是做同样工作的,这里就不再叙述了。


 


函数下面回到f_open继续执行。


Auto_mount函数早期有个转折,如果文件系统类型已经定义,则直接返回,后续代码不会执行。


 


 

文章评论0条评论)

登录后参与讨论
我要评论
0
7
关闭 站长推荐上一条 /2 下一条