基於stm32-spi2的檔案系統(暫存器)
阿新 • • 發佈:2019-02-02
=====================我是分割線============================================
最近做的spi flash,本打算弄個檔案系統,由於之前用過了JFFS、YAFFS和TrueFFS,程式碼量都相當的大,這次想找款程式碼量不那麼嚇人的,學習一下,聽說配置會相對複雜一些。選來選去,最終選定了FatFS,程式碼量足夠的小,最新的R0.09版本只有1個.c檔案(當然,還有一個底層的要自己寫,option資料夾裡的無視),老點版本就更小了。而且更新很頻繁,使用者量也夠大,就選定它了。儘管最後由於硬體和專案原因未能實際的移植它到vxWorks,但學過的還是要記錄下。
在這裡
在做具體修改之前,先大概閱讀下FatFS的原始碼,可以先讀integer.h,瞭解所用的資料型別,然後是ff.h,瞭解檔案系統所用的資料結構和各種函式宣告,再就是diskio.h,瞭解與介質相關的資料結構和操作函式。ff.c這個檔案相對較大,可以在最後將所實現的函式大致掃描一遍,之後根據使用者應用層程式呼叫函式的次序仔細閱讀相關程式碼。各個檔案都可以直接用記事本開啟查閱,非常方便。ff.h中的幾個結構體十分重要,列舉如下,首先是最基礎的檔案系統結構體:
-
/* File system object structure (FATFS) */
-
typedef struct {
-
BYTE fs_type; /* FAT子型別,一般在mount時用,置0表示未掛載*/
-
BYTE drv; /* 物理驅動號,一般為0*/
-
BYTE csize; /* 每個簇的扇區數目(1,2,4...128) */
-
BYTE n_fats; /* 檔案分配表的數目(1,2) */
-
/*FAT檔案系統依次為:引導扇區、兩個檔案分配表、根目錄區和資料區*/
-
BYTE wflag; /* 標記檔案是否被改動過,為1時要回寫*/
-
BYTE fsi_flag; /* 標記檔案系統資訊是否被改動過,為1時要回寫*/
-
WORD id; /* 檔案系統掛載ID */
-
WORD n_rootdir; /* 根目錄區入口(目錄項)的個數(用於FAT12/16)*/
-
#if _MAX_SS != 512
-
WORD ssize; /* 每扇區的位元組數(用於扇區大於512Byte的flash) */
-
#endif
-
#if _FS_REENTRANT
-
_SYNC_t sobj; /* 允許重入,即定義同步物件,用在tiny中*/
-
#endif
-
#if !_FS_READONLY
-
DWORD last_clust; /* 最後一個被分配的簇*/
-
DWORD free_clust; /* 空閒簇的個數*/
-
DWORD fsi_sector; /* 存放fsinfo的扇區(用於FAT32) */
-
#endif
-
#if _FS_RPATH
-
DWORD cdir; /* 允許相對路徑時用,儲存當前目錄起始簇(0:root)*/
-
#endif
-
DWORD n_fatent; /* FAT入口數(簇的數目 + 2)*/
-
DWORD fsize; /* 每個FAT所佔扇區*/
-
DWORD fatbase; /* FAT起始扇區*/
-
DWORD dirbase; /* 根目錄起始扇區(FAT32:Cluster#) */
-
DWORD database; /* 資料目錄起始扇區*/
-
DWORD winsect; /* 當前緩衝區中儲存的扇區號*/
-
BYTE win[_MAX_SS]; /* 單個扇區快取*/
-
} FATFS;
-
/* File object structure (FIL) */
-
typedef struct {
-
FATFS* fs; /* 所在的fs指標*/
-
WORD id; /* 所在的fs掛載編號*/
-
BYTE flag; /* 檔案狀態*/
-
BYTE pad1; /* 不知道含義,也未見程式使用*/
-
DWORD fptr; /* 檔案讀寫指標*/
-
DWORD fsize; /* 大小*/
-
DWORD sclust; /* 檔案起始簇(fsize=0時為0) */
-
DWORD clust; /* 當前簇*/
-
DWORD dsect; /* 當前資料扇區*/
-
#if !_FS_READONLY
-
DWORD dir_sect; /* 包含目錄項的扇區 */
-
BYTE* dir_ptr; /* Ponter to the directory entry in the window */
-
#endif
-
#if _USE_FASTSEEK
-
DWORD* cltbl; /*指向簇連結對映表的指標*/
-
#endif
-
#if _FS_SHARE
-
UINT lockid; /* File lock ID (index of file semaphore table) */
-
#endif
-
#if !_FS_TINY
-
BYTE buf[_MAX_SS]; /* File data read/write buffer */
-
#endif
- } FIL;
-
/* Directory object structure (DIR) */
-
typedef struct {
-
FATFS* fs; /* 同上*/
-
WORD id;
-
WORD index; /* 當前讀寫索引號 */
-
DWORD sclust; /* 檔案資料區開始簇*/
-
DWORD clust; /* 當前簇*/
-
DWORD sect; /* 當前扇區*/
-
BYTE* dir; /* 扇區快取中當前SFN入口指標,SFN含義未知,猜測和LFN類似,與檔名相關*/
-
BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
-
#if _USE_LFN
-
WCHAR* lfn; /* Pointer to the LFN working buffer */
-
WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */
-
#endif
- } DIR;
熟悉了程式碼結構後,現在開始作修改了,首先修改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檔案系統移植的文章”就可以搞定了,那裡有詳細的解決辦法