首先介紹一下window中常見的文件系統格式,包括FAT32、NTFS、exFAT。
我們嵌入式文件系統一般使用的是FAT格式。一般新的儲存芯片(EEPROM、SD卡等)內部是沒有文件系統的,他只是一個單純的能儲存數據的扇區而已,而我們需要格式化他們,才能讓我們的文件系統認識這塊芯片里的內容,並且管理他們。格式化其實就是在芯片中儲存一個結構信息,可以理解成一個全局變量,然后文件系統就是靠這個結構去索引,修改我們文件系統中的文件。
移植主要分3步:修改diskio.c文件(與硬件相關的底層接口);ffconf.c文件(修改相關的宏);格式化文件系統(如果已有文件系統可以不用格式化)
首先下載FATFS文件系統的源碼,可以到我的wp上下載:
將源碼的src目錄拷貝到我們的工程中
1.在工程中添加一個FATFS分組,並將ff.c,diskio.c添加到該分組中
添加頭文件路徑 options terget.. -> C/C++ -> include Paths
2.修改diskio.c文件,該文件是關於硬件的底層驅動,包含儲存芯片的初始化、讀寫、狀態等接口
刪除官方歷程中包含的儲存驅動頭文件,添加自己的底層驅動
#include "diskio.h" /* FatFs lower layer API */ //#include "usbdisk.h" /* Example: Header file of existing USB MSD control module */ //#include "atadrive.h" /* Example: Header file of existing ATA harddisk control module */ //#include "sdcard.h" /* Example: Header file of existing MMC/SDC contorl module */
#include "sdio_sdcard.h" //SD卡驅動
#include "SDram_file.h"
修改狀態文件系統獲取硬件底層狀態接口,我采取了一種簡單粗暴的方式,直接返回OK,什么都不做
DSTATUS disk_status ( BYTE pdrv /* Physical drive nmuber to identify the drive */ ) { DSTATUS stat = RES_OK; switch (pdrv) { case ATA : return stat; case MMC : return stat; case USB : return stat; } return STA_NOINIT; }
初始化驅動
DSTATUS disk_initialize ( BYTE pdrv /* Physical drive nmuber to identify the drive */ ) { DSTATUS stat = RES_OK; switch (pdrv) { case ATA : SD_Init(); //SD卡初始化 return stat; case MMC : return stat; case USB : return stat; } return STA_NOINIT; }
讀寫驅動,注意這里的讀寫都是對內存芯片的一個塊進行操作的,所以底層讀寫接口也應該是整個內存塊一起操作的,一般SD卡的塊大小是512字節,一些儲存芯片可能是4096個字節。
DRESULT disk_read ( BYTE pdrv, /* Physical drive nmuber to identify the drive */ BYTE *buff, /* Data buffer to store read data */ DWORD sector, /* Sector address in LBA */ UINT count /* Number of sectors to read */ ) { DRESULT res = RES_OK; switch (pdrv) { case ATA : SD_ReadDisk( buff, sector, count ); return res; case MMC : return res; case USB : return res; } return RES_PARERR; } DRESULT disk_write ( BYTE pdrv, /* Physical drive nmuber to identify the drive */ const BYTE *buff, /* Data to be written */ DWORD sector, /* Sector address in LBA */ UINT count /* Number of sectors to write */ ) { DRESULT res = RES_OK; switch (pdrv) { case ATA : SD_WriteDisk(( u8* )buff, sector, count ); return res; case MMC : return res; case USB : return res; } return RES_PARERR; }
最后還有一些其他的控制接口,比如獲取SD卡塊大小、容量等操作
DRESULT disk_ioctl ( BYTE pdrv, /* Physical drive nmuber (0..) */ BYTE cmd, /* Control code */ void *buff /* Buffer to send/receive control data */ ) { DRESULT res = RES_OK; int result; switch (pdrv) { case ATA : switch ( cmd ) { case GET_SECTOR_SIZE: *( DWORD* )buff = 512; res = RES_OK; break; case GET_BLOCK_SIZE: *( WORD* )buff = SDCardInfo.CardBlockSize; res = RES_OK; break; case GET_SECTOR_COUNT: *( DWORD* )buff = SDCardInfo.CardCapacity / 512; res = RES_OK; break; default: res = RES_PARERR; break; } return res; case MMC : return res; case USB : return res; } return RES_PARERR; } //這個是獲取時間戳,讓文件系統可以記錄文件操作的時間,這里我沒有實現這個功能,所以直接返回0,必須定義這個,如果沒有會報錯 DWORD get_fattime( void ) { return 0; }
3.修改ffconf.h文件,改文件實現文件系統的配置和裁剪,這里有幾個參數需要配置
#define _USE_MKFS 1 //是否支持格式化,我們默認0,我們要使能他
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
#define _CODE_PAGE 936 //文件系統編碼格式,我們選擇中文編碼
//是否使能長文件名,如果需要長文件名,這里改成2,並且需要在工程中添加cc936.c文件
#define _USE_LFN 0
#define _MAX_LFN 255 //文件名長度
#define _VOLUMES 1 //設備數量
//內存塊范圍,一般SD卡為512字節,有的儲存芯片一個塊可能為4096個字節
#define _MIN_SS 512
#define _MAX_SS 4096
4.最后在主程序中掛載這個卷,就可以使用我們熟悉的f_open、f_close....等功能了
FRESULT res_flash;
/* 如果沒有文件系統就格式化創建創建文件系統 */
if(f_mount(&fs,"0:",1) == FR_NO_FILESYSTEM)
{
printf("》FLASH還沒有文件系統,即將進行格式化...\r\n");
/* 格式化 */
res_flash=f_mkfs("0:",0,0);
if(res_flash == FR_OK)
{
printf("》FLASH已成功格式化文件系統。\r\n");
/* 格式化后,先取消掛載 */
res_flash = f_mount(NULL,"0:",1);
/* 重新掛載 */
res_flash = f_mount(&fs,"0:",1);
}
}