FatFs移植
注:本文移植的FatFs版本號(hào)R0.14a
一、FatFs簡(jiǎn)介
FatFs是用于小型嵌入式系統(tǒng)的通用FAT/exFAT文件系統(tǒng)模塊。FatFs模塊是按照ANSI C(C89)編寫的,與磁盤I/O層完全分離。因此它獨(dú)立于平臺(tái)。它可以集成到資源有限的小型微控制器中,如8051、PIC、AVR、ARM、Z80、RX等。這里還提供用于微型微控制器的Petit-FatFs模塊。
特征
DOS/Windows兼容的FAT/exFAT文件系統(tǒng)。
與平臺(tái)無關(guān)。易于移植。
程序代碼和工作區(qū)占用空間非常小。
支持的各種配置選項(xiàng):
ANSI/OEM或Unicode格式的長(zhǎng)文件名。
exFAT文件系統(tǒng),64位LBA和GPT,用于巨大的存儲(chǔ)空間。
線程安全的RTOS。
多個(gè)卷(物理驅(qū)動(dòng)器和分區(qū))。
可變扇區(qū)大小。
包含DBC的多個(gè)代碼頁。
只讀、可選API、I/O緩沖區(qū)等。。。
1.1 獲取最新版本
從官網(wǎng)獲取最新版本,持續(xù)更新:FatFs官網(wǎng)
如何獲取可以參考: FatFs最新版本獲取方法
1.2 目錄結(jié)構(gòu)
下載FatFs源碼包解壓后,在documents文件夾里面是一些使用的幫助文檔;在source中是FatFs文件系統(tǒng)的源代碼,source文件夾就是我們需要添加到工程中的文件。
documents文件夾里有比較詳細(xì)的幫助文檔,查看00index_e.html即可,00index_e.html文件相當(dāng)于doc文件夾內(nèi)html文件的索引頁。
source中是FatFs文件系統(tǒng)的源碼文件
diskio.c: 包含底層存儲(chǔ)介質(zhì)的操作函數(shù),這些函數(shù)需要用戶自己實(shí)現(xiàn),主要添加底層驅(qū)動(dòng)函數(shù)。
ff.c: FatFs 核心文件,文件管理的實(shí)現(xiàn)方法。該文件獨(dú)立于底層介質(zhì)操作文件的函數(shù),利用這些函數(shù)實(shí)現(xiàn)文件的讀寫。
ff.h:里面有針對(duì)文件系統(tǒng)所統(tǒng)一的字節(jié)類型:WORD、DWORD等類型,這是為了避免因內(nèi)核不同而導(dǎo)致一些字節(jié)類型的定義不統(tǒng)一。所以,關(guān)乎到文件系統(tǒng)的字節(jié)定義都是要該文件系統(tǒng)中的字節(jié)類型進(jìn)行定義就可以實(shí)現(xiàn)統(tǒng)一性。
ffconf.h:這個(gè)頭文件包含了對(duì) FatFs 功能配置的宏定義, 通過修改這些宏定義就可以裁剪 FatFs的功能。如需要支持簡(jiǎn)體中文,需要把 ffconf.h中的_CODE_PAGE 的宏改成 936 并把上面的 ffunicode.c 文件加入到工程之中。
以前的版本里有cc936.c文件等分別用于不同編碼支持,現(xiàn)在只有一個(gè)ffunicode.c實(shí)現(xiàn)。
二、FatFs移植
首先說重點(diǎn),移植只需要修改 ffconf.h 和 diskio.c 兩個(gè)文件
FatFs要求用戶提供的接口如下(主要是一些底層媒體介質(zhì)的讀寫接口):
上圖中的六個(gè)函數(shù)位于diskio.c文件中,再加上我們需要適當(dāng)?shù)男薷暮甓x,位于ffconf.h中。所以實(shí)際上我們?cè)谶M(jìn)行文件系統(tǒng)移植的時(shí)候,只需要修改ffconf.h和diskio.c兩個(gè)文件。
2.1 添加文件到工程
這里我們以STM32平臺(tái)為例,首先準(zhǔn)備一個(gè)能順利運(yùn)行的SPI-FLASH的基礎(chǔ)工程,能實(shí)現(xiàn)初始化,讀寫,擦除操作等,本示例工程應(yīng)用的型號(hào)是W25Q64,即總?cè)萘?M字節(jié)。
將下載的源碼包里的source文件夾復(fù)制到工程路徑下,更換名稱為文件名為FatFs,同時(shí)在KEIL中新建分組名為FatFs,添加三個(gè)文件diskio.c,ff.c,以及ffuicode.c,其中ffuicode.c是用于中文支持,如果不需要中文支持,可不添加。
添加 FatFs 文件夾到工程的 include 選項(xiàng)中。打開工程選項(xiàng)對(duì)話框,選擇“C/C++”選項(xiàng)下的“Include Paths”項(xiàng)目,在彈出路徑設(shè)置對(duì)話框中選擇添加“FatFs”文件夾
2.2 修改diskio.c
(1)include bsp_spi_flash.h文件,屏蔽或刪除原示例的設(shè)備物理編號(hào)宏定義,添加我們自己的宏定義,這里定義了兩個(gè),一個(gè)預(yù)留給SD卡使用,一個(gè)是我們需要用的SPI_FLASH
(2)修改disk_status 函數(shù)(原來的diskio.c文件里有該函數(shù)的示例,需要在原基礎(chǔ)上修改,后面的函數(shù)也是同理,不再贅述)
(3)修改disk_initialize 函數(shù)
/*-----------------------------------------------------------------------*/ /* 設(shè)備初始化 */ /*-----------------------------------------------------------------------*/ DSTATUS disk_initialize (BYTE pdrv /* 物理編號(hào) */ ) {uint16_t i;DSTATUS status = STA_NOINIT; switch (pdrv) {case ATA: /* SD CARD */break;case SPI_FLASH: /* SPI Flash */ /* 初始化SPI Flash */SPI_FLASH_Init();/* 延時(shí)一小段時(shí)間 */i=500;while(--i); /* 喚醒SPI Flash */SPI_Flash_WAKEUP();/* 獲取SPI Flash芯片狀態(tài) */status=disk_status(SPI_FLASH);break;default:status = STA_NOINIT;}return status; }(4)修改disk_read 函數(shù)
/*-----------------------------------------------------------------------*/ /* 讀扇區(qū):讀取扇區(qū)內(nèi)容到指定存儲(chǔ)區(qū) */ /*-----------------------------------------------------------------------*/ DRESULT disk_read (BYTE pdrv, /* 設(shè)備物理編號(hào)(0..) */BYTE *buff, /* 數(shù)據(jù)緩存區(qū) */DWORD sector, /* 扇區(qū)首地址 */UINT count /* 扇區(qū)個(gè)數(shù)(1..128) */ ) {DRESULT status = RES_PARERR;switch (pdrv) {case ATA: /* SD CARD */break;case SPI_FLASH:/* 扇區(qū)偏移2MB,外部Flash文件系統(tǒng)空間放在SPI Flash后面6MB空間 */sector+=512; SPI_FLASH_BufferRead(buff, sector <<12, count<<12);//<<12是*4096status = RES_OK;break;default:status = RES_PARERR;}return status; }(5)修改disk_write 函數(shù)
/*-----------------------------------------------------------------------*/ /* 寫扇區(qū):見數(shù)據(jù)寫入指定扇區(qū)空間上 */ /*-----------------------------------------------------------------------*/ #if FF_FS_READONLY == 0DRESULT disk_write (BYTE pdrv, /* 設(shè)備物理編號(hào)(0..) */const BYTE *buff, /* 欲寫入數(shù)據(jù)的緩存區(qū) */DWORD sector, /* 扇區(qū)首地址 */UINT count /* 扇區(qū)個(gè)數(shù)(1..128) */ ) {uint32_t write_addr; DRESULT status = RES_PARERR;if (!count) {return RES_PARERR; /* Check parameter */}switch (pdrv) {case ATA: /* SD CARD */ break;case SPI_FLASH:/* 扇區(qū)偏移2MB,外部Flash文件系統(tǒng)空間放在SPI Flash后面6MB空間 */sector+=512;write_addr = sector<<12; SPI_FLASH_SectorErase(write_addr);SPI_FLASH_BufferWrite((u8 *)buff,write_addr,count<<12);status = RES_OK;break;default:status = RES_PARERR;}return status; } #endif(6)修改disk_ioctl 函數(shù)
DRESULT disk_ioctl (BYTE pdrv, /* 物理編號(hào) */BYTE cmd, /* 控制指令 */void *buff /* 寫入或者讀取數(shù)據(jù)地址指針 */ ) {DRESULT status = RES_PARERR;switch (pdrv) {case ATA: /* SD CARD */break;case SPI_FLASH:switch (cmd) {/* 扇區(qū)數(shù)量:1536*4096/1024/1024=6(MB) */case GET_SECTOR_COUNT:*(DWORD * )buff = 1536; break;/* 扇區(qū)大小 */case GET_SECTOR_SIZE :*(WORD * )buff = 4096;break;/* 同時(shí)擦除扇區(qū)個(gè)數(shù) */case GET_BLOCK_SIZE :*(DWORD * )buff = 1;break; }status = RES_OK;break;default:status = RES_PARERR;}return status; }(7)添加get_fattime函數(shù),這里只是模擬給了一個(gè)固定的時(shí)間,不是實(shí)際的當(dāng)前時(shí)間。
get_fattime 函數(shù)用于獲取當(dāng)前時(shí)間戳,在 ff.c 文件中被調(diào)用。 FatFs 在文件創(chuàng)建、被修改時(shí)會(huì)記錄時(shí)間,這里我們直接使用賦值方法設(shè)定時(shí)間戳。為更好的記錄時(shí)間,可以使用 RTC 功能,在該函數(shù)中通過RTC獲取當(dāng)前系統(tǒng)時(shí)間即可。
具體要求返回值格式為:
bit[31:25] ——從 1980 至今是多少年,范圍是 (0…127) ;
bit[24:21] ——月份,范圍為 (1…12) ;
bit[20:16] ——該月份中的第幾日,范圍為(1…31) ;
bit[15:11]——時(shí),范圍為 (0…23);
bit[10:5] ——分,范圍為 (0…59);
bit[4:0] ——秒/ 2,范圍為 (0…29) 。
2.3 修改ffconf.h
使能用到的功能,下面只列出要修改的
#define FF_USE_MKFS 1 /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */#define FF_CODE_PAGE 936 /* This option specifies the OEM code page to be used on the target system. / Incorrect code page setting can cause a file open failure. / / 437 - U.S. / 720 - Arabic / 737 - Greek / 771 - KBL / 775 - Baltic / 850 - Latin 1 / 852 - Latin 2 / 855 - Cyrillic / 857 - Turkish / 860 - Portuguese / 861 - Icelandic / 862 - Hebrew / 863 - Canadian French / 864 - Arabic / 865 - Nordic / 866 - Russian / 869 - Greek 2 / 932 - Japanese (DBCS) / 936 - Simplified Chinese (DBCS) / 949 - Korean (DBCS) / 950 - Traditional Chinese (DBCS) / 0 - Include all code pages above and configured by f_setcp() */#define FF_USE_LFN 1 #define FF_MAX_LFN 255 /* The FF_USE_LFN switches the support for LFN (long file name). / / 0: Disable LFN. FF_MAX_LFN has no effect. / 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. / 2: Enable LFN with dynamic working buffer on the STACK. / 3: Enable LFN with dynamic working buffer on the HEAP. / / To enable the LFN, ffunicode.c needs to be added to the project. The LFN function / requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and / additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled. / The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can / be in range of 12 to 255. It is recommended to be set it 255 to fully support LFN / specification. / When use stack for the working buffer, take care on stack overflow. When use heap / memory for the working buffer, memory management functions, ff_memalloc() and / ff_memfree() exemplified in ffsystem.c, need to be added to the project. */#define FF_VOLUMES 2 /* Number of volumes (logical drives) to be used. (1-10) */#define FF_MIN_SS 512 #define FF_MAX_SS 4096配置為“#define FF_USE_LFN 1”就是將文件名存儲(chǔ)在BSS段(數(shù)據(jù)段),也就是將其作為全局變量進(jìn)行存儲(chǔ);
配置為“#define FF_USE_LFN 2”就是將 文件名存儲(chǔ)在STACK區(qū)(棧區(qū));
配置為“#define FF_USE_LFN 3”就是將文件名存儲(chǔ)在HEAP(堆區(qū))
新版本的ffconf.h里的宏都在前面新增加了FF,如FF_USE_MKFS以前是_USE_MKFS,這里了解就行。
以上步驟至此就完成了FatFs移植了。
好文推薦:
https://blog.csdn.net/qq_39778488/article/details/107129578
總結(jié)
- 上一篇: FatFs最新版本获取方法
- 下一篇: STM32关闭CAN外设的自动重传功能