一.介绍
FAT文件系统分为三层,如下图所示。
1.底层接口,包括存储媒介读/写接口(disk I/O)和供给文件创建修改时间的实时时钟,需要我们根据平台和存储介质编写移植代码。
2.中间层FATFS模块,实现了FAT 文件读/写协议。FATFS模块提供的是ff.c和ff.h。除非有必要,使用者一般不用修改,使用时将头文件直接包含进去即可。
3.最顶层是应用层,使用者无需理会FATFS的内部结构和复杂的FAT 协议,只需要调用FATFS模块提供给用户的一系列应用接口函数,如f_open,f_read,f_write 和f_close等,就可以像在PC 上读/写文件那样简单。
二、移植
1.从官网下载合适的版本的软件(http://elm-chan.org/fsw/ff/00index_e.html),本次使用FatFs R0.13b
2.把代码合并到工程中,放到一个新建文件夹下。
3.我们需要为diskio. c文件下填充下列六个函数的操作代码
disk_status-获取设备状态
disk_initialize-初始化设备
disk_read-读取数据
disk_write-写入数据
disk_ioctl-控制设备相关的功能
get_fattime-获取当前时间
(1)本次使SPI FLASH 为MX25L6406E,先添加其驱动调用的头文件。
修改以下代码,根据使用Flash数据手册修改
#define DEV_SPIFLASH 0 /* Example: Map SPI Flash to physical drive 0 */
#define FLASH_SECTOR_SIZE (4*1024) //扇区大小
#define FLASH_BLOCK_SIZE 16 //一个块有多少扇区
const unsigned short int FLASH_SECTOR_COUNT = 640; //2.5M,一个使用多少扇区用于FAT文件系统
(2)状态函数
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat;
int result;
switch (pdrv) {
case DEV_SPIFLASH:return RES_OK;
}
return STA_NOINIT;
}
(3)初始化函数
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat;
int result;
switch (pdrv) {
case DEV_SPIFLASH :
MX25LXXHal_PinInit();//引脚初设化
MX25LXXHal_SpiInit();//芯片初设化
return RES_OK;
}
return STA_NOINIT;
}
(4)读函数
/*-----------------------------------------------------------------------*/
/* 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;
int result;
int i = 0;
switch (pdrv) {
case DEV_SPIFLASH :
for(i = 0; i < count;i++)
{
MX25L1602_RD(sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE,buff);
sector++;
buff+=FLASH_SECTOR_SIZE;
}
return RES_OK;
}
return RES_PARERR;
}
(5)写函数
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;
int result;
unsigned int s;
switch (pdrv) {
case DEV_SPIFLASH :
for(s = sector;s <= sector+count-1;s++)
{
MX25L1602_Erase(s, s); // 先檫除扇区,再写入数据
}
//MX25L1602_Erase(sector, sector+count-1);
for(;count>0;count--)
{
MX25L1602_WR(sector*FLASH_SECTOR_SIZE, (u8*)buff,FLASH_SECTOR_SIZE);
sector++;
buff+=FLASH_SECTOR_SIZE;
}
return RES_OK;
}
return RES_PARERR;
}
(6)磁盘控制函数
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res;
int result;
switch (pdrv) {
case DEV_SPIFLASH :
switch(cmd)
{
case CTRL_SYNC:
res = RES_OK;
break;
case GET_SECTOR_SIZE:
*(WORD*)buff = FLASH_SECTOR_SIZE;
res = RES_OK;
break;
case GET_BLOCK_SIZE:
*(WORD*)buff = FLASH_BLOCK_SIZE;
res = RES_OK;
break;
case GET_SECTOR_COUNT:
*(DWORD*)buff = FLASH_SECTOR_COUNT;
res = RES_OK;
break;
default:
res = RES_PARERR;
break;
}
}
return res;
}
4.应用层的调用
挂载文件系统后即可调用文件操作函数,写函数最好在开辟个缓存,累计到一个扇区大小的数据再存入文件系统,这样可以做好负载均衡,避免flash使用寿命缩短。
/**
* 文件系统挂载函数
*/
int fatfs_fileSystemReset()
{
FRESULT res = 0;
res = 1;
if(res != 0)
{ printf("mount fail\n");
res = f_mkfs("0:", FM_FAT, 0, gFsWork, sizeof gFsWork);//在逻辑驱动器上创建FAT卷
if(res == 0)
{ printf("mkfs sus\n");
res = f_mount (&sysFs,"0:",1);//先挂载才能使用
if(res == 0)
{ printf("mount susu2\n");
gFsInited = 1;
return 0;
}
else {
printf("mount fail2\n");
return -1; }
}
else { printf("mkfs fail\n");
return -1; }
}
else
gFsInited = 1;
return 0;
}
5.总结
FAT文件比较小巧,适合在相对资源没有那么丰富的芯片上使用,相对于直接对FLASH操作,使用文件系统大大简化编程的难度,操作起来更加方便。