日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

FatFs 之一 R0.13c版源码目录文件、函数、全配置项详解及移植说明

發(fā)布時間:2024/10/14 编程问答 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 FatFs 之一 R0.13c版源码目录文件、函数、全配置项详解及移植说明 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

??FatFs 是用于小型嵌入式系統(tǒng)的通用 FAT/exFAT 文件系統(tǒng)模塊。FatFs 模塊的編寫符合 ANSI C(C89),并與磁盤 I/O 層完全分離,因此它獨立于硬件平臺。 它可以集成到資源有限的小型微控制器中,例如 8051,PIC,AVR,ARM,Z80,RX 等。此外,還提供用于微型微控制器的 Petit FatFs 模塊。
??看本文時需要有點 FAT 文件系統(tǒng)的基礎(chǔ),可以參考FatFs 之三 FAT文件系統(tǒng)基礎(chǔ)、FAT 數(shù)據(jù)格式、引導(dǎo)、編碼。

變更記錄

??具體參見源碼文件中的 /source/00history.txt 即可!也可以去官網(wǎng)查看。從中我們可以看到修復(fù)的各問題,尤其是源碼文件的變動。例如:在 R0.13c 中,原來獨立文件 integer.h 中的內(nèi)容被直接包含在了 ff.h 中,原來的 integer.h 被刪除!對比如下圖所示:

源碼目錄文件

??目前,最新版本為 R0.13c。相比于之前的版本,源碼有了一定的變化(參見上圖)。FatFs 的源碼包中,文件非常簡單。其源碼目錄結(jié)構(gòu)如下所示(對于簡單的文件以注釋的形式給出,核心源碼下文會詳細(xì)說明):

FatFs R0.13c │ LICENSE.txt // 版權(quán)說明 ├─documents // 配套的說明文檔 └─source00history.txt // 更新歷史記錄00readme.txt // 對于以下每個文件的功能簡介diskio.c // FATFS 與硬件的接口實現(xiàn)文件模板diskio.h // FATFS 與硬件的接口實現(xiàn)文件模板ff.c // FATFS 核心源代碼ff.h // FATFS 核心源代碼ffconf.h // FATFS 的配置文件ffsystem.c // 定義了:可選的與操作系統(tǒng)對接的各接口相關(guān)實現(xiàn)示例。ffunicode.c // 提供了 Unicode 相關(guān)的轉(zhuǎn)換函數(shù)

以下主要介紹 source 目錄下的源代碼部分!

ffconf.h

??該文件是 FatFs 的配置文件。用戶需要根據(jù)自己的需求,來修改該文件中的各配置項。在 FatFs 默認(rèn)的配置文件中,很多我們常用的函數(shù)都是被禁用的,必須修改下面的配置項來啟用。這也就意味著,直接使用默認(rèn)的配置文件一般是無法滿足我們的需求的!接下來詳細(xì)介紹一下每個配置項的具體含義及使用時需要注意的問題。以下為 FatFs 源碼中默認(rèn)的配置項說明。

FatFs Functional Configurations

FFCONF_DEF

定義了 FatFs 的版本號,與實際功能無關(guān)。 主要是 FatFs 自身用來防止出錯。具體在 ff.h 中,會檢查該文件中的改宏值是否與 ff.h 中版本一致。在 ff.h 中,有如下語句:

#if FF_DEFINED != FFCONF_DEF #error Wrong configuration file (ffconf.h). #endif

Function Configurations 功能配置

FF_FS_READONLY

定義 FatFs 是否工作在只讀模式。

  • 0:讀/寫。默認(rèn)值。
  • 1:只讀。只讀模式下,寫相關(guān)的函數(shù) f_write(), f_sync(), f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() 以及其他和寫操作相關(guān)的函數(shù)都將被移除。

FF_FS_MINIMIZE

用來極限精簡 FatFs,此選項定義最小化級別,以刪除一些基本 API 函數(shù),如下所示

  • 0:所有基本的 API 函數(shù)都可用。默認(rèn)值。
  • 1:f_stat,f_getfree,f_unlink,f_mkdir,f_chmod,f_utime,f_truncate和f_rename函數(shù)被刪除。
  • 2:除了移除 1 中的函數(shù),還將移除 f_opendir, f_readdir and f_closedir
  • 3:除了移除 2 中的函數(shù),還將移除 f_lseek

FF_USE_STRFUNC

定義字符操作的相關(guān)函數(shù) f_gets(), f_putc(), f_puts() 及 f_printf() 是否有效。

  • 0:禁用所有的字符串相關(guān)操作函數(shù)。默認(rèn)值。
  • 1:啟用,但是沒有 LF-CRLF 轉(zhuǎn)換。即:不會忽略回車符 \r
  • 2:啟用,且?guī)в?LF-CRLF轉(zhuǎn)換。即:忽略回車符 \r

FF_USE_FIND

定義目錄讀取的相關(guān)函數(shù)(f_findfirst(), f_findnext())是否有效

  • 0: 禁用。默認(rèn)值
  • 1: 啟用
  • 2: 啟用,且會檢查是否匹配 altname[]。在 1 情況下,匹配條件只有文件名。此情況下,如果 altname[]匹配也認(rèn)為是匹配的。FF_FS_MINIMIZE 必須為 0 或 1

FF_USE_MKFS

定義函數(shù) f_mkfs() 是否有效

  • 0: 禁用。默認(rèn)值
  • 1: 啟用

FF_USE_FASTSEEK

定義快速 seek 模式是否有效。

  • 0: 禁用。默認(rèn)值
  • 1: 啟用。會額外記錄很多信息,以供在 f_lseek 中使用

FF_USE_EXPAND

定義函數(shù) f_expand() 是否有效

  • 0: 禁用。默認(rèn)值
  • 1: 啟用

FF_USE_CHMOD

定義屬性操作函數(shù) f_chmod() 和 f_utime() 是否有效

  • 0: 禁用。默認(rèn)值
  • 1: 啟用。此外必須定義 FF_FS_READONLY 為 0。即:不能開啟只讀模式

FF_USE_LABEL

定義卷標(biāo)函數(shù) f_getlabel() 和 f_setlabel() 是否有效

  • 0: 禁用。默認(rèn)值
  • 1: 啟用

FF_USE_FORWARD

定義函數(shù) f_forward() 是否有效

  • 0: 禁用。默認(rèn)值
  • 1: 啟用

Locale and Namespace Configurations 本地化和命名空間設(shè)置

FF_CODE_PAGE

指定要在目標(biāo)系統(tǒng)上使用的 OEM 代碼頁,錯誤的編碼頁設(shè)置將導(dǎo)致讀寫文件失敗。支持的編碼頁如下:

取值編碼頁
0包括以下的所有代碼頁并由 f_setcp() 配置
437U.S.
720Arabic
737Greek
771KBL
775Baltic
850Latin 1
852Latin 2
855Cyrillic
857Turkish
860Portuguese
861Icelandic
862Hebrew
863Canadian French
864Arabic
865Nordic
866Russian
869Greek 2
932Japanese (DBCS)
936Simplified Chinese (DBCS)
949Korean (DBCS)
950Traditional Chinese (DBCS)

如果路徑名未使用任何非ASCII字符,則任何代碼頁設(shè)置之間都沒有區(qū)別,將它設(shè)置為 437 即可。

關(guān)于編碼頁,可以參考一下博文 FatFs 之 路徑規(guī)則、字符編碼、編碼頁、卷管理詳解。

FF_USE_LFN

??此選項可切換對長文件名(LFN)的支持。 啟用 LFN 時,需要將 Unicode 支持模塊 ffunicode.c 添加到項目中。 當(dāng)使用堆棧作為工作緩沖區(qū)時,請注意堆棧溢出。 當(dāng)使用堆內(nèi)存作為工作緩沖區(qū)時,需要將 ffsystem.c 添加到項目中,并實現(xiàn)其中的內(nèi)存管理函數(shù) ff_memalloc 和 ff_memfree。

  • 0: 不啟用。默認(rèn)值。FF_MAX_LFN 無效
  • 1: 啟用。且 LFN 在代碼段 BSS 上具有靜態(tài)工作緩沖區(qū)。 始終不是線程安全的。
  • 2: 啟用。且在 STACK 上具有動態(tài)工作緩沖區(qū)的 LFN。需要注意棧溢出的問題。
  • 3: 啟用。且在 HEAP 上具有動態(tài)工作緩沖區(qū)的 LFN。此時,必須要啟用 ffsystem.c 中的動態(tài)內(nèi)存申請函數(shù) ff_memalloc() 和 ff_memfree()

注意:長文件名與上面的編碼頁有關(guān)系!有些編碼頁就是 Unicode 字符集,也因此需要長文件名支持!

關(guān)于長文件名,可以參考一下博文 FatFs 之 路徑規(guī)則、字符編碼、編碼頁、卷管理詳解。

FF_MAX_LFN

??啟用 LFN ,會增加 (FF_MAX_LFN + 1) * 2 字節(jié)的固定緩沖區(qū)空間。具體使用方式見 ff.c 文件的開頭部分的宏定義即可。如果是 exFAT 文件系統(tǒng),則還需要再占用 (FF_MAX_LFN + 44) / 15 * 32 字節(jié)的緩沖區(qū)空間。且 exFAT 必須啟用長文件名支持
??FF_MAX_LFN 以 UTF-16 代碼單位定義工作緩沖區(qū)的大小,它可以在 12 到 255 的范圍內(nèi)。建議將 255 設(shè)置為完全支持LFN規(guī)范。長文件名是微軟的專利,使用中與上面的編碼有關(guān)系。

FF_LFN_UNICODE

??此選項可在 API 上切換文件名的字符編碼。選擇 Unicode 時,FF_CODE_PAGE 實際上沒有任何意義,除了與遺留系統(tǒng)的兼容性,例如 MS-DOS 和任何不支持 LFN 的系統(tǒng)。 FatFs 支持代碼點達(dá)到 U + 10FFFF。

  • 0: ANSI/OEM in current CP (TCHAR = char)。默認(rèn)值
  • 1: Unicode in UTF-16 (TCHAR = WCHAR)
  • 2: Unicode in UTF-8 (TCHAR = char)
  • 3: Unicode in UTF-32 (TCHAR = DWORD)

此外,字符串輸入/輸出函數(shù)的行為也會受到此選項的影響。如果關(guān)閉了長文件名支持,則該項無效!

FF_LFN_BUF 和 FF_SFN_BUF

??這組選項在 FILINFO 結(jié)構(gòu)中定義了文件名成員 fname[] 和 altname[] 的大小,FILINFO 結(jié)構(gòu)用于讀取目錄項。這些值應(yīng)該足夠讀取文件名。讀取文件名的最大可能長度取決于API上的字符編碼,如下所示:

EncodingLFN lengthSFN length
ANSI/OEM at SBCS255 items12 items
ANSI/OEM at DBCS510 items12 items
Unicode in UTF-16/32255 items12 items
Unicode in UTF-8765 items34 items

如果名稱成員的大小不足以用于LFN,則該項目將被視為沒有LFN。 如果未啟用LFN,則這些選項無效。

FF_STRF_ENCODE

??當(dāng) API 上的字符編碼為 Unicode(FF_LFN_UNICODE> = 1)時,字符串 I/O 函數(shù),f_gets,f_putc,f_puts和 f_printf 將轉(zhuǎn)換其中的字符編碼。 此選項定義了要通過這些函數(shù)讀取/寫入的文件的字符編碼。 當(dāng)LFN 未啟用或 FF_LFN_UNICODE 為 0 時,字符串函數(shù)在沒有任何編碼轉(zhuǎn)換的情況下工作,此選項無效。

取值文件字符編碼
0ANSI/OEM in current code page
1Unicode in UTF-16LE
2Unicode in UTF-16BE
3Unicode in UTF-8

FF_FS_RPATH

定義是否支持相對路徑

  • 0: 禁用。且相對路徑相關(guān)的函數(shù)也被移除
  • 1: 支持。f_chdir() 和 f_chdrive() 有效
  • 2: 支持。除了提供 1 中的函數(shù),還提供 f_getcwd()

Volume/Drive Configurations 驅(qū)動器/卷配置

FF_VOLUMES

此選項配置要使用的卷數(shù)(邏輯驅(qū)動器最多10個),最小值 1。

FF_STR_VOLUME_ID

??此選項定義對字符串卷ID的支持。當(dāng)為驅(qū)動器前綴啟用任意卷ID字符串時,可以使用 FF_VOLUME_STRS 預(yù)定義的字符串或用戶定義的字符串作為路徑名稱中的驅(qū)動器前綴。無論該選項是什么,數(shù)字驅(qū)動器號總是有效的,而且該選項還可以啟用驅(qū)動器前綴的任何一種格式。

取值描述示例
0僅 DOS/Windows 風(fēng)格的數(shù)字ID前綴可用0:/filename
1DOS/Windows 風(fēng)格的字符串ID前綴也可用flash:/filename
2Unix 風(fēng)格的字符串ID前綴也可用/flash/filename

FF_VOLUME_STRS

??此選項定義每個邏輯驅(qū)動器的卷ID字符串。項目數(shù)不得少于FF_VOLUMES。 卷ID字符串的有效字符是A-Z,a-z和0-9,但是,它們在不區(qū)分大小寫的情況下進行比較。
??如果 FF_STR_VOLUME_ID == 0,則此選項無效。 如果 FF_STR_VOLUME_ID > = 1且未定義此選項,則需要定義用戶定義的卷字符串表,如下所示。 該表不應(yīng)動態(tài)修改。

/* User defined volume ID strings for 0: 1: 2: 3: ... */ const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sdc","usb"};

FF_MULTI_PARTITION

??禁用(0)或啟用(1)。 此選項可切換多分區(qū)功能。 默認(rèn)情況下(0),每個邏輯驅(qū)動器號綁定到相同的物理驅(qū)動器號,并且僅安裝物理驅(qū)動器中的卷。 啟用后,每個邏輯驅(qū)動器都綁定到用??戶定義的分區(qū)解析表 VolToPart [] 中列出的物理驅(qū)動器上的分區(qū)。 此外,還將提供 f_fdisk功能。

FF_MIN_SS, FF_MAX_SS

??這組選項定義了低級磁盤 I/O 接口,disk_read 和 disk_write函數(shù)使用的扇區(qū)大小范圍。 有效值為 512、1024、2048 和 4096。FF_MIN_SS定義最小扇區(qū)大小,FF_MAX_SS 定義最大扇區(qū)大小。 始終為存儲卡和硬盤設(shè)置 512。 但是,板載閃存和某些類型的光學(xué)介質(zhì)可能需要更大的值。 當(dāng)FF_MAX_SS > FF_MIN_SS 時,啟用對可變扇區(qū)大小的支持,并且需要對 disk_ioctl 函數(shù)實現(xiàn) GET_SECTOR_SIZE 命令。

FF_USE_TRIM

定義是否支持 ATA-TRIM

  • 0: 禁止
  • 1: 支持。此時,disk_ioctl() 函數(shù)需要實現(xiàn) CTRL_TRIM 命令。

FF_FS_NOFSINFO

??取值 0 到 3。如果您需要知道FAT32 卷上的正確可用空間,請設(shè)置此選項的第0位,并且在卷 mount 后第一時間執(zhí)行 f_getfree函數(shù),將強制進行完整的FAT掃描。 位1 控制最后分配的簇編號的使用。

取值描述
bit0=0Use free cluster count in the FSINFO if available.
bit0=1Do not trust free cluster count in the FSINFO.
bit1=0Use last allocated cluster number in the FSINFO to find a free cluster if available.
bit1=1Do not trust last allocated cluster number in the FSINFO.

System Configurations (嵌入式)操作系統(tǒng)相關(guān)的配置

FF_FS_TINY

??取值為 正常(0)或微小(1)。 在微小的配置中,文件對象 FIL 的大小減少了 FF_MAX_SS 字節(jié)。 不是從文件對象中消除私有數(shù)據(jù)緩沖區(qū),而是將文件系統(tǒng)對象 FATFS 中的公共扇區(qū)緩沖區(qū)用于文件數(shù)據(jù)傳輸。

FF_FS_EXFAT

??此選項定義對 exFAT 文件系統(tǒng)的支持,Enabled(1)或 Disabled(0)。開啟之后,將同時支持 exFAT、FAT/FAT32。要啟用 exFAT,還必須啟用LFN 并為全功能 exFAT 功能配置 FF_LFN_UNICODE> = 1 和 FF_MAX_LFN == 255。 請注意,由于需要64位整數(shù)類型,啟用 exFAT會丟棄ANSI C(C89)兼容性。

FF_FS_NORTC

??此選項控制時間戳功能,0:使用RTC;1:不使用 RTC。 如果系統(tǒng)沒有任何 RTC 功能或不需要有效時間戳,請將 FF_FS_NORTC 設(shè)置為1 以禁用時間戳功能。此時,FatFs 修改的每個對象都有一個由 FF_NORTC_MON,FF_NORTC_MDAY 和 FF_NORTC_YEAR 定義的固定時間戳。 要使用時間戳功能,請設(shè)置 FF_FS_NORTC == 0 并將 get_fattime 函數(shù)添加到項目中以從 RTC 獲取當(dāng)前時間。 此選項對只讀配置無效。

FF_NORTC_MON, FF_NORTC_MDAY, FF_NORTC_YEAR

這組選項定義了在無 RTC 系統(tǒng)中使用的時間。 此選項在只讀配置或 FF_FS_NORTC == 0 時無效。

FF_FS_LOCK

??選項切換文件鎖定功能,以控制打開重復(fù)文件和打開對象的非法操作。 請注意,文件鎖定功能獨立于重入。 只讀配置時,此選項必須為 0。

取值描述
0禁用文件鎖定功能。 為避免文件操作錯誤導(dǎo)致文件崩潰,應(yīng)用程序需要避免非法打開,刪除和重命名為打開的對象。
>0啟用文件鎖定功能。 該值定義在文件鎖定控制下可以同時打開多少文件/子目錄。 使用FR_LOCKED將拒絕對打開對象的非法操作。

FF_FS_REENTRANT

??此選項可切換 FatFs 模塊本身的重入(線程安全),取值為 禁用(0)或啟用(1)。 請注意,對不同卷的文件/目錄訪問始終是可重入的,無論此選項如何,它都可以同時工作。但是,卷管理函數(shù) f_mount,f_mkfs 和 f_fdisk 始終不可重入。
??只有文件/目錄訪問同一個卷,換句話說,獨占使用每個文件系統(tǒng)對象,才能受此功能的控制。 要啟用此功能,用戶需要將 ffsystem.c 添加到自己的項目中,同時實現(xiàn)其中的同步處理程序 ff_req_grant,ff_rel_grant,ff_del_syncobj和ff_cre_syncobj。

FF_FS_TIMEOUT

??當(dāng)?shù)却龝r間太長時,使用 FF_FS_TIMEOUT中止文件功能的時間滴答數(shù)。 當(dāng) FF_FS_REENTRANT == 0 時,此選項無效。

FF_SYNC_t

??此選項定義 OS 相關(guān)的同步對象類型。 例如 HANDLE,ID,OS_EVENT *,SemaphoreHandle_t等。用于OS 定義的頭文件需要包含在 ff.c范圍內(nèi)的某處。 當(dāng) FF_FS_REENTRANT == 0 時,此選項無效。

ff.c/h

??這兩個文件是 FatFs 的核心源碼文件。所有的 FatFs 的操作函數(shù)均位于這個了文件中。我們在使用時,使用的 API 也均是出自于這兩個文件。
?? 其中各函數(shù)比較多,后續(xù)單獨來介紹!

ffsystem.c

??當(dāng)使用了操作系統(tǒng)時,該文件必須要由用戶來實現(xiàn)!源碼包中的 ffsystem.c 給出了需要實現(xiàn)的各函數(shù)接口!用戶需要根據(jù)自己使用的操作系統(tǒng),修改其中的各接口的實現(xiàn)。注意:即使不使用系統(tǒng),如果我們啟用了長文件名,且長文件名的配置為 3,則也必須要實現(xiàn)以下兩個動態(tài)內(nèi)存申請函數(shù)! 下面我們看看該文件中的各個函數(shù)接口

動態(tài)內(nèi)存申請

??該文件中的第一部分函數(shù)就是動態(tài)內(nèi)存申請接口。當(dāng)然,其受制于在ffconf.h中的配置項FF_USE_LFN的限制。也就說,如果不使用長文件名,則 FatFs 不需要使用動態(tài)內(nèi)存申請。 標(biāo)準(zhǔn)接口和標(biāo)準(zhǔn)C語言類似,就是名字稍有變化,有以下兩個:

  • void* ff_memalloc (UINT msize); 申請動態(tài)內(nèi)存
  • msize: 要申請的內(nèi)存的大小
  • 返回值:成功,返回指向申請的內(nèi)存的指針;失敗返回空指針
  • void ff_memfree (void* mblock); 釋放之前申請的動態(tài)內(nèi)存
  • mblock: 之前申請的動態(tài)內(nèi)存的指針
  • 返回值: 無
  • ??為什么要自定義這兩個函數(shù)?在使用了嵌入式操作系統(tǒng)之后,嵌入式操作系統(tǒng)一般都會提供對內(nèi)存的管理功能。其一般也會重新定義動態(tài)內(nèi)存的相關(guān)函數(shù),而不是直接使用標(biāo)準(zhǔn) C 語言定義的 malloc 和 free 函數(shù)。

    可重入性

    ??該文件中的第二部分函數(shù)是與系統(tǒng)緊密相關(guān)的相關(guān)的函數(shù)接口。這主要用來處理在多任務(wù)操作系統(tǒng)中,多線程操作相關(guān)的問題。在單線程進程(單任務(wù))中,只存在一個控制流。因此,這些進程所執(zhí)行的代碼無需重入或著說是線程安全的。但是在多線程(多任務(wù))程序中,相同的功能和資源可以通過多個控制流并發(fā)訪問。
    ??FatFs 使用了同步對象(Synchronization Object)這個稱呼,在實際系統(tǒng)中,通常為 信號量 或者 互斥量。當(dāng)然,也不局限于這兩種。
    ??以下為 FatFs 默認(rèn)提供的示例代碼。其中給出了常用的系統(tǒng)下的基本操作。如果使用其中的一種,則直接修改注釋即可,否則,需要根據(jù)自己使用的系統(tǒng)來修改。

    創(chuàng)建同步對象

    該函數(shù)在 f_mount() 函數(shù)中被調(diào)用,用來為指定的卷創(chuàng)建一個同步對象。

    int ff_cre_syncobj ( /* 1:成功, 0:失敗 */BYTE vol, /* 對應(yīng)卷(邏輯驅(qū)動器號) */FF_SYNC_t* sobj /* 返回創(chuàng)建的同步信號量的指針 */ ) {/* Win32 */*sobj = CreateMutex(NULL, FALSE, NULL);return (int)(*sobj != INVALID_HANDLE_VALUE);/* uITRON */ // T_CSEM csem = {TA_TPRI,1,1}; // *sobj = acre_sem(&csem); // return (int)(*sobj > 0);/* uC/OS-II */ // OS_ERR err; // *sobj = OSMutexCreate(0, &err); // return (int)(err == OS_NO_ERR);/* FreeRTOS */ // *sobj = xSemaphoreCreateMutex(); // return (int)(*sobj != NULL);/* CMSIS-RTOS */ // *sobj = osMutexCreate(&Mutex[vol]); // return (int)(*sobj != NULL); }

    刪除同步對象

    這個函數(shù)在f mount()函數(shù)中調(diào)用,以刪除使用ff_cre_syncobj ()函數(shù)創(chuàng)建的同步對象。

    int ff_del_syncobj ( /* 返回值:1:成功, 0:刪除失敗 */FF_SYNC_t sobj /* 要刪除的同步對象 */ ) {/* Win32 */return (int)CloseHandle(sobj);/* uITRON */ // return (int)(del_sem(sobj) == E_OK);/* uC/OS-II */ // OS_ERR err; // OSMutexDel(sobj, OS_DEL_ALWAYS, &err); // return (int)(err == OS_NO_ERR);/* FreeRTOS */ // vSemaphoreDelete(sobj); // return 1;/* CMSIS-RTOS */ // return (int)(osMutexDelete(sobj) == osOK); }

    鎖定卷

    此函數(shù)在輸入文件函數(shù)時調(diào)用,以鎖定卷。

    int ff_req_grant ( /* 返回值:1:獲取鎖定許可, 0:失敗 */FF_SYNC_t sobj /* Sync object to wait */ ) {/* Win32 */return (int)(WaitForSingleObject(sobj, FF_FS_TIMEOUT) == WAIT_OBJECT_0);/* uITRON */ // return (int)(wai_sem(sobj) == E_OK);/* uC/OS-II */ // OS_ERR err; // OSMutexPend(sobj, FF_FS_TIMEOUT, &err)); // return (int)(err == OS_NO_ERR);/* FreeRTOS */ // return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE);/* CMSIS-RTOS */ // return (int)(osMutexWait(sobj, FF_FS_TIMEOUT) == osOK); }

    釋放卷

    此函數(shù)在離開文件函數(shù)以解鎖卷時調(diào)用。

    void ff_rel_grant (FF_SYNC_t sobj /* Sync object to be signaled */ ) {/* Win32 */ReleaseMutex(sobj);/* uITRON */ // sig_sem(sobj);/* uC/OS-II */ // OSMutexPost(sobj);/* FreeRTOS */ // xSemaphoreGive(sobj);/* CMSIS-RTOS */ // osMutexRelease(sobj); }

    ffunicode.c

    ??該文件很大,用來處理 Unicode 編碼相關(guān)的功能。如果在以上配置中,啟用了相關(guān)功能,則需要將該文件添加到自己的項目中。用戶無需修改其中的任何內(nèi)容。所有函數(shù)均由 FatFs 調(diào)用!
    ?? FatFs 建議,如果系統(tǒng)中存在 Unicode 相關(guān)的處理函數(shù),則應(yīng)該以系統(tǒng)自帶的為準(zhǔn),盡量減少對該文件的使用即可!

    diskio.c/h

    ??由于 FatFs 模塊是獨立于平臺和存儲介質(zhì)的文件系統(tǒng)層,因此它與物理設(shè)備(例如存儲卡,硬盤和任何類型的存儲設(shè)備)完全分離。 低級設(shè)備控制模塊不是 FatFs 模塊的一部分,需要由使用者提供。
    ??diskio.c/h 這兩個文件用于實現(xiàn) FatFs 與硬件的交互。其中定義了 FatFs 與硬件交互使用的接口。FatFs 中的這兩個文件僅僅是個模板,用戶需要根據(jù)需要來實現(xiàn)其中的各接口,并不能直接使用!其中:

    • diskio.h: 其中聲明了各接口的形式以及一些 FatFs 使用的宏,用戶不得更改!ff.c 直接包含該頭文件,并使用該文件中定義的一些內(nèi)容!
    • diskio.c: 其中存放了需要用戶實現(xiàn)的各接口!用戶需要根據(jù)自己的硬件平臺(RAM、MMC、USB等)以及 ffcong.h中的配置(例如,配置項 FF_USE_TRIM定義為 1,則需要在 disk_ioctl() 函數(shù)中實現(xiàn)對 CTRL_TRIM 命令的處理)

    ??一般的使用了 FatFs 的第三方庫,都會提供該文件的實現(xiàn)!我們可以參考。例如,在 STM32 的USB 驅(qū)動庫中,有個名為 usbh_msc_fatfs.c 的文件,它其實就是 diskio.c 改了個名字而已。里面的函數(shù)就是 diskio.h 所聲明的那些函數(shù)!也因此在使用 STM32 的USB 驅(qū)動庫 + FatFs 時,我們不再需要 diskio.c了,但是 diskio.h 仍然是必須的!
    下面我們來看看具體的各函數(shù)

    DSTATUS disk_status (BYTE pdrv);

    FatFs 調(diào)用此函數(shù),查詢當(dāng)前驅(qū)動器狀態(tài)

    • 參數(shù):
      • pdrv:用于標(biāo)識目標(biāo)設(shè)備的物理驅(qū)動器號。 單驅(qū)動系統(tǒng)始終為零。
    • 返回值:當(dāng)前驅(qū)動器狀態(tài)以下面描述的狀態(tài)標(biāo)志的組合返回(狀態(tài)宏值是按位定義并使用的,具體見 diskio.h)。 FatFs 僅使用了 STA_NOINIT 和 STA_PROTECT 這兩個。
      • STA_NOINIT:表示設(shè)備尚未初始化且未準(zhǔn)備好工作。 此標(biāo)志在系統(tǒng)重置,介質(zhì)刪除或 disk_initialize 功能失敗時設(shè)置。 在disk_initialize函數(shù)成功后清除它。 必須捕獲異步發(fā)生的任何介質(zhì)更改并將其反映到狀態(tài)標(biāo)志,否則自動安裝功能將無法正常工作。 如果系統(tǒng)不支持介質(zhì)更改檢測,則應(yīng)用程序需要在每次更改介質(zhì)后使用 f_mount 函數(shù)顯式重新裝入卷。
      • STA_NODISK:表示驅(qū)動器中沒有介質(zhì)。 在固定磁盤驅(qū)動器上清除這項始終被清除。 請注意,FatFs 不會使用此標(biāo)志。
      • STA_PROTECT:表示介質(zhì)受寫保護。 在沒有寫保護功能的驅(qū)動器上始終清除此值。 如果設(shè)置了STA_NODISK,則此項無效。

    DSTATUS disk_initialize (BYTE pdrv);

    FatFs 調(diào)用此函數(shù),以初始化存儲設(shè)備

    • 參數(shù):
      • pdrv:用于標(biāo)識目標(biāo)設(shè)備的物理驅(qū)動器號。 單驅(qū)動系統(tǒng)始終為零。
    • 返回值:與 disk_status 的返回值相同!

    此函數(shù)初始化存儲設(shè)備并使其準(zhǔn)備好進行通用讀/寫。 當(dāng)函數(shù)成功時,返回值中的STA_NOINIT標(biāo)志被清除。此功能需要受FatFs模塊的控制。 應(yīng)用程序不得調(diào)用此函數(shù),否則可能會破壞卷上的FAT結(jié)構(gòu)。 要重新初始化文件系統(tǒng),請改用f_mount函數(shù)。

    DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);

    FatFs 調(diào)用此函數(shù),以從存儲設(shè)備的扇區(qū)讀取數(shù)據(jù)

    • 參數(shù):
      • pdrv:用于標(biāo)識目標(biāo)設(shè)備的物理驅(qū)動器號。
      • buff:指向存儲讀取數(shù)據(jù)的字節(jié)數(shù)組的第一項的指針。 讀取數(shù)據(jù)的大小將是扇區(qū)大小*計數(shù)字節(jié)。
      • sector:32 位 LBA(Logical Block Address,邏輯區(qū)塊地址) 的開始扇區(qū)號。
      • count:要讀取的扇區(qū)數(shù)。
    • 返回值:
      • RES_OK:成功
      • RES_ERROR:在讀取操作期間發(fā)生了不可恢復(fù)的硬錯誤。
      • RES_PARERR:無效的參數(shù)
      • RES_NOTRDY:設(shè)備尚未初始化。

    ??對通用存儲設(shè)備(例如存儲卡,hadddisk和光盤)的讀/寫操作是以稱為扇區(qū)的數(shù)據(jù)字節(jié)塊為單位完成的。 FatFs支持512到4096字節(jié)范圍內(nèi)的扇區(qū)大小。 當(dāng)FatF配置為固定扇區(qū)大小(FF_MIN_SS == FF_MAX_SS,這是大多數(shù)情況)時,讀/寫功能必須以該扇區(qū)大小工作。 當(dāng)FatFs配置為可變扇區(qū)大小(FF_MIN_SS <FF_MAX_SS)時,在disk_initialize函數(shù)成功后立即使用disk_ioctl函數(shù)查詢media的扇區(qū)大小。
    ??buff 指定的內(nèi)存地址并不總是與字邊界對齊,因為參數(shù)定義為BYTE* 類型。 未對齊的讀/寫請求可以在直接傳輸時發(fā)生。 如果總線體系結(jié)構(gòu)(尤其是DMA控制器)不允許未對齊的內(nèi)存訪問,則應(yīng)在此函數(shù)中處理該問題。 下面介紹了一些解決方法以避免此問題。

    • 在此函數(shù)中使用某些方法將字轉(zhuǎn)換為字節(jié)來進行傳輸。
    • 在 f_read() 調(diào)用中,避免包含整個扇區(qū)的長讀取請求。 - 任何直接傳輸都不會發(fā)生。
    • 在 f_read(fp, dat, btw, bw) 調(diào)用中,確保 (((UINT)dat & 3) == (f_tell(fp) & 3)) 為真。 - 保證了 buff 的字對齊。

    此外,DMA 可能無法訪問內(nèi)存區(qū)域。如果內(nèi)存區(qū)域位于通常用于堆棧的緊密耦合的內(nèi)存中,情況就是這樣。使用雙緩沖傳輸,或者避免將任何文件 I/O 緩沖區(qū)、FATFS 和 FIL 結(jié)構(gòu)定義為堆棧中的局部變量。
    通常,多扇區(qū)讀請求不能被分割成對存儲設(shè)備的單扇區(qū)事務(wù),否則讀吞吐量會變得更差。

    DRESULT disk_write (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);

    FatFs 調(diào)用此函數(shù),將數(shù)據(jù)寫入存儲設(shè)備的扇區(qū)

    • 參數(shù):
      • pdrv:用于標(biāo)識目標(biāo)設(shè)備的物理驅(qū)動器號。
      • buff:指向要寫入的字節(jié)數(shù)組的第一項的指針。 要寫入的數(shù)據(jù)大小是扇區(qū)大小*計數(shù)字節(jié)。
      • sector:32 位 LBA(Logical Block Address,邏輯區(qū)塊地址) 的開始扇區(qū)號。
      • count:要寫的扇區(qū)數(shù)。
    • 返回值:
      • RES_OK:成功
      • RES_ERROR:在寫入操作期間發(fā)生了不可恢復(fù)的硬錯誤。
      • RES_WRPRT:介質(zhì)是寫保護的
      • RES_PARERR:無效的參數(shù)
      • RES_NOTRDY:設(shè)備尚未初始化。

    ??指定的內(nèi)存地址并不總是與字邊界對齊,因為參數(shù)定義為 BYTE*。 有關(guān)更多信息,請參閱 disk_read 函數(shù)的說明。
    ??通常,多扇區(qū)寫請求(計數(shù)> 1)不得拆分為存儲設(shè)備的單扇區(qū)事務(wù),否則文件寫吞吐量將大幅降低。
    ??FatFs期望磁盤控制層的寫入功能延遲。 該函數(shù)返回后,寫操作可能并沒有完成,因為媒體介質(zhì)可能正在執(zhí)行寫操作或者 僅僅是將數(shù)據(jù)放到了媒體介質(zhì)的緩沖區(qū)中。但是從此函數(shù)返回后,buff 中的數(shù)據(jù)將無效。 寫完成請求由 disk_ioctl 函數(shù)的 CTRL_SYNC 命令完成。 因此,如果實現(xiàn)延遲寫入功能,則將改善文件系統(tǒng)的寫入吞吐量。

    DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);

    FatFs 調(diào)用此函數(shù),來控制設(shè)備特定的功能和除通用讀/寫之外的其他功能。

    • 參數(shù):
      • pdrv:用于標(biāo)識目標(biāo)設(shè)備的物理驅(qū)動器號。
      • cmd:命令代碼,在 diskio.h 中有定義。
      • buff:指向參數(shù)的指針,是否有意義取決于命令代碼。 如果命令代碼不需要傳遞該參數(shù),則忽略即可。
    • 返回值:
      • RES_OK (0):成功
      • RES_ERROR:出錯
      • RES_PARERR:命令代碼或參數(shù)無效。
      • RES_NOTRDY:設(shè)備尚未初始化。

    FatFs模塊僅需要五個與設(shè)備無關(guān)的命令,如下所述:

    命令描述
    CTRL_SYNC用來確保設(shè)備已完成了掛起的寫入過程。 如果磁盤 I/O 模塊或存儲設(shè)備具有回寫高速緩存,則必須立即將標(biāo)記為臟的高速緩存數(shù)據(jù)寫回介質(zhì)。 如果在 disk_write 函數(shù)內(nèi)完成對介質(zhì)的每個寫操作,此命令中無需任何處理。
    GET_SECTOR_COUNT將驅(qū)動器上的可用扇區(qū)數(shù)返回到 buff 指向的 DWORD 類型的變量中。 f_mkfs 和 f_fdisk 函數(shù)使用此命令來確定要創(chuàng)建的卷/分區(qū)大小。 在配置了 FF_USE_MKFS == 1 時,必須要實現(xiàn)對該名利的處理。
    GET_SECTOR_SIZE將設(shè)備的扇區(qū)大小返回到 buff 指向的 WORD 類型的變量中。 此命令的有效返回值為 512,1024,2048和4096. 僅當(dāng)FF_MAX_SS > FF_MIN_SS 時才需要此命令。 當(dāng) FF_MAX_SS == FF_MIN_SS 時,從不使用此命令,并且設(shè)備必須以該扇區(qū)大小工作。
    GET_BLOCK_SIZE將以扇區(qū)為單位將閃存介質(zhì)的擦除塊大小返回到 buff 指向的 DWORD 類型的變量中。 允許值為 1 到 32768的 2 次方。如果擦除塊大小未知或非閃存介質(zhì),則返回1。 該命令僅由 f_mkfs 函數(shù)使用,它嘗試對齊擦除塊邊界上的數(shù)據(jù)區(qū)域。 在FF_USE_MKFS == 1 時 必須實現(xiàn)對改命令的處理
    CTRL_TRIM通知設(shè)備不再需要扇區(qū)塊上的數(shù)據(jù),并且可以擦除它。 扇區(qū)塊由 buff 指向的DWORD數(shù)組 {,} 指定。 這是一個與 ATA 設(shè)備修剪完全相同的命令。 如果不支持此功能或閃存設(shè)備不支持此命令,則無需執(zhí)行此操作。 FatFs 不檢查結(jié)果代碼,即使扇區(qū)塊沒有被很好地擦除,文件功能也不會受到影響。 該命令在刪除簇和 在 f_mkfs 函數(shù)中被調(diào)用。 在 FF_USE_TRIM == 1 時必須實現(xiàn)對改命令的處理

    FatFs從不使用任何依賴于設(shè)備的命令或用戶定義的命令。下表顯示了一個可能對某些應(yīng)用程序有用的非標(biāo)準(zhǔn)命令示例。

    命令描述
    CTRL_FORMAT在媒體上創(chuàng)建物理格式。 如果 buff 不為 null,則它是指向進度通知的回調(diào)函數(shù)的指針。
    CTRL_POWER_IDLE將設(shè)備置于空閑狀態(tài)。 如果設(shè)備通過通用讀/寫功能進入活動狀態(tài),則可能不會設(shè)置當(dāng)前狀態(tài)標(biāo)志中的STA_NOINIT。
    CTRL_POWER_OFF將設(shè)備置為關(guān)閉狀態(tài)。 如果需要,關(guān)閉設(shè)備電源并取消初始化設(shè)備接口。 必須設(shè)置當(dāng)前狀態(tài)標(biāo)志中的STA_NOINIT。 設(shè)備通過disk_initialize功能進入活動狀態(tài)。
    CTRL_LOCK鎖定介質(zhì)彈出機制。
    CTRL_UNLOCK解鎖媒體彈出機制。
    CTRL_EJECT彈出介質(zhì)盒。 功能成功后,將設(shè)置狀態(tài)標(biāo)志中的STA_NOINIT和STA_NODISK。
    CTRL_GET_SMART閱讀SMART信息。
    MMC_GET_TYPE獲取卡類型。 類型標(biāo)志bit0:MMCv3,bit1:SDv1,bit2:SDv2 +和bit3:LBA存儲在buff指向的BYTE變量中。 (MMC / SDC特定命令)
    MMC_GET_CSD將CSD寄存器讀入buff指向的16字節(jié)緩沖區(qū)。 (MMC / SDC特定命令)
    MMC_GET_CID將CID寄存器讀入buff指向的16字節(jié)緩沖區(qū)。 (MMC / SDC特定命令)
    MMC_GET_OCR將OCR寄存器讀入buff指向的4字節(jié)緩沖區(qū)。 (MMC / SDC特定命令)
    MMC_GET_SDSTAT將SDSTATUS寄存器讀入buff指向的64字節(jié)緩沖區(qū)。 (SDC特定命令)
    ATA_GET_REV將修訂字符串轉(zhuǎn)換為buff指向的16字節(jié)緩沖區(qū)。 (ATA / CFC特定命令)
    ATA_GET_MODEL將模型字符串放入buff指向的40字節(jié)緩沖區(qū)中。 (ATA / CFC特定命令)
    ATA_GET_SN將序列號字符串放入buff指向的20字節(jié)緩沖區(qū)中。 (ATA / CFC特定命令)
    ISDIO_READ讀取由buff指向的命令結(jié)構(gòu)指定的iSDIO寄存器塊。 (FlashAir特定命令)
    ISDIO_WRITE將數(shù)據(jù)塊寫入由buff指向的命令結(jié)構(gòu)指定的iSDIO寄存器。 (FlashAir特定命令)
    ISDIO_MRITE更改由buff指向的命令結(jié)構(gòu)指定的iSDIO寄存器中的位。 (FlashAir特定命令)

    移植說明

    第一步:源碼文件整理

    ??根據(jù)上面的介紹,其中,ff.c、ff.h、ffconf.h、diskio.c、diskio.h 這六個文件是最基本的,必須要包含在我們的項目中!除此之外,根據(jù)自己的配置:

    • 如果需要 FatFs 支持可重入, 則 必須要包含 ffsystem.c, 且必須實現(xiàn) ffsystem.c 中的 ff_req_grant(), ff_rel_grant(), ff_del_syncobj() 和 ff_cre_syncobj() 這四個函數(shù)!
    • 如果需要 FatFs 支持長文件名,則必須要包含 ffunicode.c,如果配置長文件名模式為 3 (FF_USE_LFN == 3),則必須同時包含 ffsystem.c, 且必須實現(xiàn) ffsystem.c 中的 ff_memalloc() 和 ff_memfree() 這兩個函數(shù)。

    第二步:修改配置

    ??根據(jù)自己的需要修改 ffconf.h 中的各個配置項!

    第三步:實現(xiàn)必要的函數(shù)

    ??首先要實現(xiàn) diskio.c/h 其中各接口!需要注意的是,一般的使用了 FatFs 的第三方庫,都會提供該文件的實現(xiàn)!例如,在 STM32 的USB 驅(qū)動庫中,有個名為 usbh_msc_fatfs.c 的文件,它其實就是 diskio.c 改了個名字而已。里面的函數(shù)就是 diskio.h 所聲明的那些函數(shù)!也因此在使用 STM32 的USB 驅(qū)動庫 + FatFs 時,我們不再需要 diskio.c了,但是 diskio.h 仍然是必須的!
    下表顯示了需要實現(xiàn)的函數(shù)(部分需要看自己在ffconf.h 的配置):

    在 FatFs 源碼的 diskio.c 中給出的示例是以默認(rèn)的配置來說的,在 ffconf.h 中,有如下配置:

    /*---------------------------------------------------------------------------/ / Drive/Volume Configurations 驅(qū)動器/卷配置 /---------------------------------------------------------------------------*//* 要使用的卷(邏輯驅(qū)動器)數(shù)。 取值 1 ~ 10*/ #define FF_VOLUMES 1 /* Number of volumes (logical drives) to be used. (1-10) *//* 這兩個宏值用來給每個卷定義一個名字* 0: 不啟用卷名字,默認(rèn)值* 1 或 2: 對應(yīng)的卷名由 FF_VOLUME_STRS 給出。 FF_VOLUME_STRS 的個數(shù)必須小于 FF_VOLUMES。* 名字的規(guī)則為 A-Z, a-z and 0-9 組合,且字母開頭。不區(qū)分大小寫!* 如果定義為了 >= 1 但是沒有定義 FF_VOLUME_STRS,則 用戶必須自己定義 const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",...* * 在 ff.c 中,我們可以發(fā)現(xiàn)如下語句:* #if FF_STR_VOLUME_ID* #ifdef FF_VOLUME_STRS* static const char* const VolumeStr[FF_VOLUMES] = {FF_VOLUME_STRS};* #endif* #endif*/ #define FF_STR_VOLUME_ID 0 #define FF_VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3" /* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. / When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive / number in the path name. FF_VOLUME_STRS defines the volume ID strings for each / logical drives. Number of items must not be less than FF_VOLUMES. Valid / characters for the volume ID strings are A-Z, a-z and 0-9, however, they are / compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is / not defined, a user defined volume string table needs to be defined as: / / const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... */

    我們必須根據(jù)自己的需求來更改。結(jié)合上文對于這個文件中每個函數(shù)的說明來實現(xiàn)即可!

    第四步:實現(xiàn) get_fattime

    ??如果在 ffconf.h 中配置了 FF_FS_NORTC == 0,則必須自己實現(xiàn)函數(shù) DWORD get_fattime (void); 該函數(shù)返回一個 4 字節(jié)的時間戳!例如在上面的 STM32 的 USB 中,在 usbh_msc_fatfs.c 中 有 該函數(shù)的實現(xiàn),但是默認(rèn)為空(根據(jù)配置,用戶需要修改該函數(shù)實現(xiàn))!
    ??如果在 ffconf.h 中配置了 FF_FS_NORTC == 1,則可省略該函數(shù)的實現(xiàn)!具體見上文的說明即可!

    該函數(shù)的格式:DWORD get_fattime (void);

    • 參數(shù):
    • 返回值:當(dāng)前本地時間應(yīng)作為包含在DWORD值中的位字段返回。 位字段如下:
      • bit31:25:從 1980 年開始的年份 ,取值 0 ~ 127。例如 37 for 2017)
      • bit24:21:月份(1…12)
      • bit20:16:日期 (1…31)
      • bit15:11:小時(0…23)
      • bit10:5:分鐘 (0…59)
      • bit4:0:秒 / 2 ( 0…29, e.g. 25 for 50)

    第五步:應(yīng)用層使用

    ??經(jīng)過以上四步之后,就可以在項目中使用 FatFs了。可用的接口全部在于 ff.h 中,其與標(biāo)準(zhǔn) C 語言中各函數(shù)用法基本一致!

    error: #20: identifier “BYTE” is undefined

    ??這個問題應(yīng)該是是由于沒有正確包含頭文件導(dǎo)致的。在 R0.13c 的時候,作者更新: Supported stdint.h for C99 and later. (integer.h was included in ff.h),然后刪除了原來的 integer.h。這樣,diskio.h 中也刪除了對于該文件的包含。這樣就導(dǎo)致了 diskio.h 中某些數(shù)據(jù)類型未定義!如下圖:

    解決方法就是在 diskio.h 中包含數(shù)據(jù)類型的定義文件。根據(jù) 00history.txt 中的更新說明,現(xiàn)在的數(shù)據(jù)類型定義就在 ff.h 中。

    參考

  • ST 官網(wǎng)
  • FatFs 官網(wǎng)
  • 總結(jié)

    以上是生活随笔為你收集整理的FatFs 之一 R0.13c版源码目录文件、函数、全配置项详解及移植说明的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。