文件系統對於嵌入式系統的重要性是不言而喻的,有了文件系統管理數據和外設變得方便許多,同時簡化了應用的開發。今天我們來以在SPI_FLASH上建立文件系統爲例,看看FATFS文件系統怎麼移植和使用。
需要準備的材料有:
(1)FATFS文件系統源碼(點此下載最新FATFS源碼)。
(2)單片機平臺一個(內存大一些更好)。
(3)SPI_FLASH芯片一個(如:W25Q32)。
FATFS是一個通用的嵌入式文件系統,對不同的平臺支持很好,大到硬盤、U盤、存儲卡,小到spi_flash芯片甚至單片機內部FLASH都可以使用FATFS。今天我們就在一個4M大小的SPI_FLASH( W25Q32 )上建立一個文件系統,主控制器是飛思卡爾K60單片機。在做文件系統移植前,你需要把操作SPI_FLASH的驅動調通,能讀寫SPI_FLASH就可以了。
step 0.1:下載最新的FATFS源碼,當前版本:R0.13。
step 0.2 解壓縮新下載的FATFS源碼,看看裏面都是些什麼文件。如下圖所示,紅色框是移植FATFS所必須的文件,藍色框內的文件是可選的移植文件。
diskio.c個diskio.h是和存儲器讀寫控制相關的驅動接口,比如SPI_FLASH的讀寫函數接口,都要映射到這裏面。必須的文件
ff.h和ff.h是FATFS的核心文件,必須的文件
ffconf.h是FATFS的配置文件,用來裁剪FATFS,必須的文件
integer.h是FATFS所用到的數據類型定義,用以兼容不同字長CPU,必須的文件
ffsystem.c是一些關於在帶操作系統平臺中,使用的示例,可選文件
ffunicode.c是萬國碼編碼文件,文件裏主要是大數組定義,假如你需要讓文件名支持中文就需要這個文件,這個文件會使代碼空間急劇變大,可選文件
step 0.3 本次FATFS移植未使用操作系統,文件系統支持中文路徑和名稱,所以需要ff.c、ff.h、ffconf.h、diskio.c、diskio.h、ffunicode.c和integer.h這六個文件添加到工程中即可。如下圖:
step 1.0 修改ffconf.h文件,來裁剪我們的FATFS,通過宏開關來去掉不用的功能,來精簡文件系統。想知道每個宏的功能?(點擊這裏)
需要注意的是:由於我們此次移植支持了中文路徑和名稱,所以這個要設置這個宏 #define FF_CODE_PAGE936 /*936代表 簡體中文*/
step 1.1 修改diskio.c 來映射我們的存儲器讀寫控制接口,如下:
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2016 */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be */
/* attached to the FatFs via a glue function rather than modifying it. */
/* This is an example of glue functions to attach various exsisting */
/* storage control modules to the FatFs module with a defined API. */
/*-----------------------------------------------------------------------*/
#include "diskio.h" /* FatFs lower layer API */
#include "w25qxx.h"
#include "debug.h"
#define DISKIO_DEBUG 1
#if defined DISKIO_DEBUG&&(DISKIO_DEBUG)
#define diskio_printf uart_printf
#else
#define diskio_printf(a,...)
#endif
/* Definitions of physical drive number for each drive */
#define SPI_FLASH 0 /* Example: Map Ramdisk to physical drive 0 */
/*-----------------------------------------------------------------------*/
/* Get Drive Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
if(pdrv == SPI_FLASH)
{
return RES_OK; //直接返回OK即可
}
else
{
diskio_printf("!!!disk_status ERR\r\n");
return RES_PARERR;
}
}
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
if(pdrv == SPI_FLASH)
{
w25qxx_init();//初始化 spi flash
return RES_OK;
}
else
{
diskio_printf("!!!disk_initialize ERR\r\n");
return RES_PARERR;
}
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Start sector in LBA */
UINT count /* Number of sectors to read */
)
{
DRESULT res;
//uart_printf("disk_read---sector:%d,count:%d\r\n",sector,count);
if(pdrv == SPI_FLASH)
{
res = FS_SpiFlash_Read(buff,sector,count);//spi flash的讀接口,注意函數參數類型一致性
return res;
}
else
{
diskio_printf("!!!disk_read ERR\r\n");
return RES_PARERR;
}
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_write (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Start sector in LBA */
UINT count /* Number of sectors to write */
)
{
DRESULT res;
if(pdrv == SPI_FLASH)
{
res = FS_SpiFlash_Write((uint8_t *)buff,sector,count);//spi flash的寫接口,注意函數參數類型一致性
return res;
}
else
{
diskio_printf("!!!disk_write ERR\r\n");
return RES_PARERR;
}
}
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
if (pdrv == SPI_FLASH)
{
switch (cmd)
{
case CTRL_SYNC:
return RES_OK;
/* 扇區數量 1024*1024*1024 =4 (MB) */
case GET_SECTOR_COUNT:
*(DWORD * )buff = 1024;//W25Q32 有1024個大小爲4k bytes 的扇區
return RES_OK;
/* 扇區大小 */
case GET_SECTOR_SIZE :
*(WORD * )buff = 4096;//spi flash的扇區大小是 4K Bytes
return RES_OK;
/*塊大小 */
case GET_BLOCK_SIZE :
*(DWORD * )buff = 1;
return RES_OK;
default:
return RES_PARERR;
}
}
else
{
diskio_printf("!!!disk_ioctl ERR\r\n");
return RES_PARERR;
}
}
DWORD get_fattime(void)
{
DWORD time;
/* 返回當前時間戳 */ //暫不添加時間獲取,需要的話就把RTC數據傳入這裏
return 0;
}
要修改的文件就這麼多了,其他文件直接使用,不用改動。
step2.0 下面寫個測試函數,來測測我們移植成功 了沒有。
void fs_test(void)
{
FATFS fs; /* Filesystem object */
FIL fil; /* File object */
FRESULT res; /* API result code */
UINT bw; /* Bytes written */
BYTE work[FF_MAX_SS]; /* Work area (larger is better for processing time) */
BYTE mm[50];
UINT i;
uart_printf("文件系統測試開始:\r\n");
/* 格式化文件系統 */
res = f_mkfs("0:", FM_ANY, 0, work, sizeof work);//"0:"是卷標,來自於 #define SPI_FLASH 0
if (res)
{
uart_printf("文件系統格式化失敗.\r\n");
return ;
}
else
{
uart_printf("文件系統格式化成功.\r\n");
}
/* 掛載文件系統 */
res = f_mount(&fs, "0:", 0);
if (res)
{
uart_printf("文件系統掛載失敗.\r\n");
}
else
{
uart_printf("文件系統掛載成功.\r\n");
}
/* Create a file as new */
res = f_open(&fil, "0:/測試文件.txt", FA_CREATE_NEW|FA_WRITE|FA_READ);
if (res)
{
uart_printf("打開文件失敗.\r\n");
}
else
{
uart_printf("打開文件成功.\r\n");
}
/* Write a message */
res = f_write(&fil, "Hello,World!", 12, &bw);
//uart_printf("res write:%d\r\n",res);
if (bw == 12)
{
uart_printf("寫文件成功!\r\n");
}
else
{
uart_printf("寫文件失敗!\r\n");
}
res = f_size(&fil);
uart_printf("文件大小:%d Bytes.\r\n",res);
memset(mm,0x0,50);
f_lseek(&fil,0);
res = f_read(&fil,mm,12,&i);
if (res == FR_OK)
{
uart_printf("讀文件成功!\r\n");
uart_printf("讀到數據長度:%d Bytes.\r\n",i);
}
else
{
uart_printf("讀文件失敗!\r\n");
}
uart_printf("讀到如下數據:\r\n");
buff_print((char *)mm,12);
/* Close the file */
f_close(&fil);
/*卸載文件系統*/
f_mount(0, "0:", 0);
uart_printf("文件系統測試完畢.\r\n");
step2.1 Congratulations!!!瞧, 我們成功了,盡情享用文件系統帶來的便利吧。
說的比較淺顯,大家有問題或建議歡迎留言。over