本文摘自《STM32 HAL 库开发实战指南 —基于野火 F407 霸天虎开发板》
FatFs源文件说明
- option 文件夹下是一些可选的外部 c 文件,包含了多语言支持需要用到的文件和转换
函数。 - diskio.c 文件是 FatFs 移植最关键的文件,它为文件系统提供了最底层的访问 SPI Flash
芯片的方法,FatFs 有且仅有它需要用到与 SPI Flash 芯片相关的函数。diskio.h 定义了 FatFs 用到的宏,以及 diskio.c 文件内与底层硬件接口相关的函数声明。 - 00history.txt 介绍了 FatFs 的版本更新情况。
- 00readme.txt 说明了当前目录下 diskio.c 、diskio.h、ff.c、ff.h、integer.h 的功能。
- integer.h:文件中包含了一些数值类型定义。
- diskio.c:包含底层存储介质的操作函数,这些函数需要用户自己实现,主要添加
底层驱动函数。 - ff.c: FatFs 核心文件,文件管理的实现方法。该文件独立于底层介质操作文件的
函数,利用这些函数实现文件的读写。 - cc936.c:本文件在 option 目录下,是简体中文支持所需要添加的文件,包含了简
体中文的 GBK 和 Unicode 相互转换功能函数。 - ffconf.h:这个头文件包含了对 FatFs 功能配置的宏定义,通过修改这些宏定义就可
以裁剪 FatFs 的功能。如需要支持简体中文,需要把 ffconf.h 中的_CODE_PAGE 的宏改成 936 并把上面的 cc936.c 文件加入到工程之中。
移植过程讲解
FatFs 组件是 FatFs 的主体,文件都在源码 src 文件夹中,其中 ff.c、ff.h、integer.h 以及 diskio.h 四个文件我们不需要改动,只需要修改 ffconf.h 和 diskio.c 两个文件。
ffconf.h 主要是配置FatFs 要支持什么功能 diskio.c 是FatFs 与底层的接口,需要自己实现
1、支持简体中文
为支持简体中文长文件名称需要添加 ff_convert 和 ff_wtoupper 函数,实际这两个 已经在 cc936.c 文件中实现了,我们只要直接把 cc936.c 文件添加到工程中就可以了。
2、必须移植的功能函数
- 设备状态获取
DSTATUS disk_status (BYTE pdrv) //,pdrv是设备的物理编号,状态异常返回STA_NOINIT - 设备初始化
DSTATUS disk_initialize(BYTE pdrv) - 扇区读取
DRESULT disk_read ( BYTE pdrv, /* 设备物理编号(0…) */ BYTE buff, / 数据缓存区 / DWORD sector, / 扇区首地址 / UINT count / 扇区个数(1…128) */ ) BYTE 类型实际是 unsigned char 类型,DWORD 类型实际是 unsigned long 类型,UINT 类型实际是 unsigned int 类型,类型定义在 integer.h 文件中。
3、创建文件,写入文件的功能函数
当 ffconf.h 内宏定义_FS_READONLY == 0时,需要支持以下函数
- 扇区写入
DRESULT disk_write ( BYTE pdrv, /* 设备物理编号(0…) */ const BYTE buff, / 欲写入数据的缓存区 / DWORD sector, / 扇区首地址 / UINT count / 扇区个数(1…128) */ ) - 其他控制
DRESULT disk_ioctl ( BYTE pdrv, /* 物理编号 / BYTE cmd, / 控制指令 */ void buff / 写入或者读取数据地址指针 */ ) cmd 为控制指令,包括发出同步信号、获取扇区数目、获取扇区大小、获取擦除块数量等等指令,buff 为指令对应的数据指针 - 时间戳获取
__weak DWORD get_fattime(void) get_fattime 函数用于获取当前时间戳,在 ff.c 文件中被调用。FatFs 在文件创建、被修 改时会记录时间,这里我们直接使用赋值方法设定时间戳。为更好的记录时间,可以使用 控制器 RTC 功能,
4、FatFs 功能配置
其他函数的移植,用到很少,就以上6个函数移植完,就可以实现大部分常用功能了。
- #define _USE_MKFS 1
格式化功能选择,为使用 FatFs 格式化功能,需要把它设置为 1 - #define _CODE_PAGE 936
语言功能选择,并要求把相关语言文件添加到工程宏。 - #define _USE_LFN 2
长文件名支持,默认不支持长文件名,这里配置为 2,支持长文件名,并指定使用栈空间为缓冲区。 - #define _VOLUMES 2
指定物理设备数量,这里设置为 2,包括预留 SD 卡和 SPI Flash 芯片。 - #define _MIN_SS 512
- #define _MAX_SS 4096
指定扇区大小的最小值和最大值。SD 卡扇区大小一般都为 512 字节,SPI Flash 芯片扇区大小一般设置为 4096 字节,所以需要把_MAX_SS改为 4096。
FatFs 功能使用
1、FatFs常用变量说明
- FATFS fs FatFs 文件系统对象
FATFS 是在 ff.h 文件定义的一个结构体类型,针对的对象是物理设备,包含了物理设备的物理编号、扇区大小等等信息,一般我们都需要为每个物理设备定义一个 FATFS 变量。 - FIL fnew 文件对象
FIL 也是在 ff.h 文件定义的一个结构体类型,针对的对象是文件系统内具体的文件,包含了文件很多基本属性,比如文件大小、路径、当前读写地址等等。如果需要在同一时间打开多个文件进行读写,才需要定义多个 FIL 变量,不然一般定义一个 FIL 变量即可。 - FRESULT res_flash 文件操作结果
FRESULT 是也在 ff.h 文件定义的一个枚举类型,作为 FatFs 函数的返回值类型,主要管理 FatFs 运行中出现的错误。总共有 19 种错误类型,包括物理设备读写错误、找不到文件、没有挂载工作空间等等错误。这在实际编程中非常重要,当有错误出现是我们要停止文件读写,通过返回值我们可以快速定位到错误发生的可能地点。如果运行没有错误才返回 FR_OK。 - UINT fnum 文件成功读写数量
fnum 是个 32 位无符号整形变量,用来记录实际读取或者写入数据的数组
2、文件系统初始化
- Flash 挂载文件系统,文件系统挂载时会对 SPI 设备初化
res_flash = f_mount(&fs,"1:",1);
if (res_flash == FR_NO_FILESYSTEM) {
printf("》FLASH 还没有文件系统,即将进行格式化.. .\r\n");
}
else if (res_flash!=FR_OK) {
printf("!!外部 Flash 挂载文件系统失败。(%d)\r\n",res_flash);
printf("!!可能原因:SPI Flash 初始化不成功。\r\n");
while (1);
}
else {
printf("》文件系统挂载成功,可以进行读写测试\r\n");
}
res_flash=f_mkfs("1:",0,0);
if (res_flash == FR_OK) {
printf("》FLASH 已成功格式化文件系统。\r\n");
res_flash = f_mount(NULL,"1:",1);
res_flash = f_mount(&fs,"1:",1);
} else {
LED_RED;
printf("《《格式化失败。》》\r\n");
while (1);
}
res_flash = f_open(&fnew, "1:FatFs 读写测试文件.txt",FA_CREATE_ALWAYS | FA_WRITE );
if ( res_flash == FR_OK )
{
printf("》打开/创建 FatFs 读写测试文件.txt 文件成功,向文件写入数据。\r\n");
res_flash=f_write(&fnew,WriteBuffer,sizeof(WriteBuffer),&fnum);
if (res_flash==FR_OK)
{
printf("》文件写入成功,写入字节数据:%d\n",fnum);
printf("》向文件写入的数据为:\r\n%s\r\n",WriteBuffer);
}
else
{
printf("!!文件写入失败:(%d)\n",res_flash);
}
f_close(&fnew);
}
else
{
printf("!!打开/创建文件失败。\r\n");
}
res_flash = f_open(&fnew, "1:FatFs 读写测试文件.txt", FA_OPEN_EXISTING | FA_READ);
if (res_flash == FR_OK) {
printf("》打开文件成功。\r\n");
res_flash = f_read(&fnew, ReadBuffer, sizeof(ReadBuffer), &fnum);
if (res_flash==FR_OK)
{
printf("》文件读取成功,读到字节数据:%d\r\n",fnum);
printf("》读取得的文件数据为:\r\n%s \r\n", ReadBuffer);
}
else
{
printf("!!文件读取失败:(%d)\n",res_flash);
}
}
else
{
printf("!!打开文件失败。\r\n");
}
f_close(&fnew);
}
|