FAT移植建議

最近做的spi flash,本打算弄個文件系統,由於之前用過了JFFS、YAFFS和TrueFFS,代碼量都相當的大,這次想找款代碼量不那麼嚇人的,學習一下,聽說配置會相對複雜一些。選來選去,最終選定了FatFS,代碼量足夠的小,最新的R0.09版本只有1個.c文件(當然,還有一個底層的要自己寫,option文件夾裏的無視),老點版本就更小了。而且更新很頻繁,用戶量也夠大,就選定它了。儘管最後由於硬件和項目原因未能實際的移植它到vxWorks,但學過的還是要記錄下。

    在這裏http://elm-chan.org/fsw/ff/00index_e.html下載源碼,只有800多K,小的可憐,還可以下載示例程序,有AVR、Win32、lpc等多平臺已實現的方案。打開看src文件夾,一個option文件夾、00readme.txt、diskio.h、ff.c、ff.h、ffconf.h和interger.h。移植時需要修改的文件主要包括ffconf.h和interger.h,後者是在它的定義與目標平臺上的有衝突,或者用的不習慣時修改的。

    在做具體修改之前,先大概閱讀下FatFS的源代碼,可以先讀integer.h,瞭解所用的數據類型,然後是ff.h,瞭解文件系統所用的數據結構和各種函數聲明,再就是diskio.h,瞭解與介質相關的數據結構和操作函數。ff.c這個文件相對較大,可以在最後將所實現的函數大致掃描一遍,之後根據用戶應用層程序調用函數的次序仔細閱讀相關代碼。各個文件都可以直接用記事本打開查閱,非常方便。ff.h中的幾個結構體十分重要,列舉如下,首先是最基礎的文件系統結構體:

  1. /* File system object structure (FATFS) */  
  2. typedef struct {  
  3.     BYTE    fs_type;        /* FAT子類型,一般在mount時用,置0表示未掛載*/  
  4.     BYTE    drv;            /* 物理驅動號,一般爲0*/  
  5.     BYTE    csize;          /* 每個簇的扇區數目(1,2,4...128) */  
  6.     BYTE    n_fats;         /* 文件分配表的數目(1,2) */  
  7.     /*FAT文件系統依次爲:引導扇區、兩個文件分配表、根目錄區和數據區*/  
  8.     BYTE    wflag;          /* 標記文件是否被改動過,爲1時要回寫*/  
  9.     BYTE    fsi_flag;       /* 標記文件系統信息是否被改動過,爲1時要回寫*/  
  10.     WORD    id;             /* 文件系統掛載ID */  
  11.     WORD    n_rootdir;      /* 根目錄區入口(目錄項)的個數(用於FAT12/16)*/  
  12. #if _MAX_SS != 512  
  13.     WORD    ssize;          /* 每扇區的字節數(用於扇區大於512Byte的flash) */  
  14. #endif  
  15. #if _FS_REENTRANT  
  16.     _SYNC_t sobj;           /* 允許重入,即定義同步對象,用在tiny中*/  
  17. #endif  
  18. #if !_FS_READONLY  
  19.     DWORD   last_clust;     /* 最後一個被分配的簇*/  
  20.     DWORD   free_clust;     /* 空閒簇的個數*/  
  21.     DWORD   fsi_sector;     /* 存放fsinfo的扇區(用於FAT32) */  
  22. #endif  
  23. #if _FS_RPATH  
  24.     DWORD   cdir;           /* 允許相對路徑時用,存儲當前目錄起始簇(0:root)*/  
  25. #endif  
  26.     DWORD   n_fatent;       /* FAT入口數(簇的數目 + 2)*/  
  27.     DWORD   fsize;          /* 每個FAT所佔扇區*/  
  28.     DWORD   fatbase;        /* FAT起始扇區*/  
  29.     DWORD   dirbase;        /* 根目錄起始扇區(FAT32:Cluster#) */  
  30.     DWORD   database;       /* 數據目錄起始扇區*/  
  31.     DWORD   winsect;        /* 當前緩衝區中存儲的扇區號*/  
  32.     BYTE    win[_MAX_SS];   /* 單個扇區緩存*/  
  33. } FATFS;  

 然後是與之相關的文件和文件夾結構體,附上具體註釋:

  1. /* File object structure (FIL) */  
  2. typedef struct {  
  3.     FATFS*  fs;             /* 所在的fs指針*/  
  4.     WORD    id;             /* 所在的fs掛載編號*/  
  5.     BYTE    flag;           /* 文件狀態*/  
  6.     BYTE    pad1;           /* 不知道含義,也未見程序使用*/  
  7.     DWORD   fptr;           /* 文件讀寫指針*/  
  8.     DWORD   fsize;          /* 大小*/  
  9.     DWORD   sclust;         /* 文件起始簇(fsize=0時爲0) */  
  10.     DWORD   clust;          /* 當前簇*/  
  11.     DWORD   dsect;          /* 當前數據扇區*/  
  12. #if !_FS_READONLY  
  13.     DWORD   dir_sect;       /* 包含目錄項的扇區 */  
  14.     BYTE*   dir_ptr;        /* Ponter to the directory entry in the window */  
  15. #endif  
  16. #if _USE_FASTSEEK  
  17.     DWORD*  cltbl;          /*指向簇鏈接映射表的指針*/  
  18. #endif  
  19. #if _FS_SHARE  
  20.     UINT    lockid;         /* File lock ID (index of file semaphore table) */  
  21. #endif  
  22. #if !_FS_TINY  
  23.     BYTE    buf[_MAX_SS];   /* File data read/write buffer */  
  24. #endif  
  25. } FIL;  

 下面是目錄的:

  1. /* Directory object structure (DIR) */  
  2. typedef struct {  
  3.     FATFS*  fs;             /* 同上*/  
  4.     WORD    id;  
  5.     WORD    index;          /* 當前讀寫索引號 */  
  6.     DWORD   sclust;         /* 文件數據區開始簇*/  
  7.     DWORD   clust;          /* 當前簇*/  
  8.     DWORD   sect;           /* 當前扇區*/  
  9.     BYTE*   dir;            /* 扇區緩存中當前SFN入口指針,SFN含義未知,猜測和LFN類似,與文件名相關*/  
  10.     BYTE*   fn;             /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */  
  11. #if _USE_LFN  
  12.     WCHAR*  lfn;            /* Pointer to the LFN working buffer */  
  13.     WORD    lfn_idx;        /* Last matched LFN index number (0xFFFF:No LFN) */  
  14. #endif  
  15. } DIR;  

    其他類似f_mount、f_open等接口API就不細說了,在掛載的時候其實真正起作用的是chk_mounted函數,在這裏纔會將掛載分區的相關信息分配到FatFS結構體中;還有一個get_fat函數,也比較重要,在f_open和許多目錄操作的函數中都有用到,而且FAT入口這個表達也十分晦澀,而它又調用了一個move_window的函數,也是十分晦澀難懂,可能是我英語太爛的緣故吧。實際上,move_window的作用是改變文件系統的當前工作扇區,如果要遷移到的是當前扇區,直接返回,如果不是,就將原扇區寫回,若是FAT表,還要寫進備份區。

    熟悉了代碼結構後,現在開始作修改了,首先修改ffconf.h文件配置與硬件相關的文件系統特性,然後自己添加一套底層操作即可。先看ffconf.h,裏面定義了很多宏,可以根據自己需要一一配置:

    先看功能配置:

_FS_TINY:文件系統爲標準的還是微型的,默認爲標準的(0);

_FS_READONLY:文件系統是否爲只讀,默認爲可讀寫(0),若只讀則f_write、f_sync、 f_unlink、f_mkdir、f_chmod、f_rename、f_truncate和f_getfree不可用;

_FS_MINIMIZE:裁剪文件系統的功能,默認爲全部功能(0),若爲1、2則會移除大部分鏈接、目錄等功能;

_USE_STRFUNC:是否允許字符串操作,默認爲不允許(0),這個看個人需求,一般情況下設置爲1即可,如果工作在windows下,爲保證文件兼容性(如換行符’\n’和回車符’\r’)建議將此項設置爲2;

_USE_MKFS:是否允許使用f_mkfs函數,默認爲0,用於創建文件夾,建議開啓;

_USE_FORWARD:用於允許f_forward函數,只有開啓tiny文件系統時纔用到,該函數用於將讀寫的數據立即轉存到數據流中,以節省RAM空間;

_USE_FASTSEEK:是否開啓快速索引,默認爲0,開啓後,會使用FIL結構體中的cltbl元素來加快搜索;

_CODE_PAGE:指定目標系統使用的OEM代碼頁,默認爲日語(932),改爲936簡體中文;OEM是什麼意思呢?在OS編碼中,unicode是一種雙字節字符編碼,無論中文還是英文,或者其他語言統一到2個字節,它與現有的任何編碼(ASCII,GB等)都不兼容。WindowsNT(2000)的內核即使用該編碼,所有數據進入內核前轉換成UNICODE,退出內核後在轉換成版本相關的編碼(通常稱爲OEM,在簡體中文版下即爲GB);

_USE_LEN、_MAX_LEN、_LFN_UNICODE:這三個的意思不是很清楚,但是確定是與長文件名有關的,不建議開啓,否則又要多加函數,麻煩;

_FS_RPATH:是否允許相對路徑,讓我選擇就不開啓,否則邏輯變得複雜不說,代碼量也變多了一些;

    再看硬件相關配置:

_VOLUMES:磁盤(flash)邏輯卷數,默認爲1,不建議修改;

_MAX_SS:扇區大小,默認512Byte,最大可設置4096Byte;

_MULTI_PARTITION:分區選項,默認爲0,即一個分區,若想要多分區可自行設置;

_USE_ERASE:是否允許扇區擦除,默認爲0,若開啓則要在disk_ioctl函數中添加擦除命令代碼;

    最後是文件系統配置:

_WORD_ACCESS:數據遞進格式,默認爲0,即以字節爲單位遞進,兼容性更強,若你的系統最新單位爲字(2Byte),則可設爲1;

_FS_REENTRANT、_FS_TIMEOUT、_SYNC_t:這三個選項與文件系統是否允許重入有關,所直白點,就是能否被多線程同時訪問,像RTOS中,一般建議開啓,_SYNC_t可定義爲對應OS中的操作對象,windows下爲HANDLE,uCos中爲OS_EVENT,vxWorks中爲SEMAPHORE。另外,開啓後還需要添加ff_req_grant、ff_rel_grant和ff_del_syncobj三個函數,實際上實現的功能就是申請互斥量、釋放互斥量和刪除互斥量的意思,可以定義OS封裝即可;

_FS_SHARE:和上面的類似,表示文件系統最大允許同時打開多少文件,默認爲0,即只能打開一個。

    在配置這些選項的時候,可以根據定義閱讀ff.c文件中的相關代碼,基本上能對整體的結果有了瞭解,完成了ffconf.h後,再就是編寫底層接口了,在新一點的FatFs中,並未提供函數接口模版,可以下老版的拷過來,也可以打開doc文件夾下的幫助文檔00index_e.htm文件,裏面有底層函數接口的格式及各個參數的描述。至於底層驅動,我只做過spi flash的,這個可以參考我上一篇文章。需要注意的是,底層讀寫函數中的參數sector指的是扇區的序號,需要自己換算成驅動接口中的字節位置。

    到這裏,移植基本完成了,如果你的文件系統出現LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr))有問題(數據異常終止DATA ABORT exception之類的)的情況,請百度搜索“轉一篇比較詳細介紹FatFS文件系統移植的文章”就可以搞定了,那裏有詳細的解決辦法。

  1. <pre code_snippet_id="87127" snippet_file_name="blog_20131128_1_499580" name="code" class="csharp"><span style="font-size:18px"></span>  
  2. </pre>  
  3. <pre></pre> 
發佈了36 篇原創文章 · 獲贊 8 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章