STM32文件系统的移植
首先介绍一下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);
}
}