STM32移植最新版FATFS
FATFS源码下载
http://elm-chan.org/fsw/ff/00index_e.html
添加 FATFS 源码到工程
-
解压下载的 FATFS 源码包,将
ff.c
、ff.h
、ffsystem.h
、ffconf.h
、diskio.h
复制到工程目录下的一个新文件夹(例如FatFS
)中。 -
keil中添加源文件和路径,省略
编译并修改错误
完成上述操作,对整个工程代码进行编译后,出现了如下13个报错信息,通过定位报错信息可以得知,主要是由于文件系统diskio.c中对MMC、RAM、USB设备的初始化、读、写、状态获取API未定义和ff.c中对文件时间戳未定义。
因此,接下来对文件系统的移植操作主要是针对报错信息进行处理,将diskio.c文件中的硬件设备初始化、读、写、状态获取API及ff.c文件时间戳进行适配、定义实现。
这个错误是默认FATFS是使能RTC功能的,这里可以将其关闭
在“ffconf.h”配置文件中将这个宏设为1即可
实现diskio.c
文件
diskio.c
文件包含了 FATFS 与底层存储设备的接口函数,需要根据实际使用的存储设备进行实现。以下是一些常见的接口函数:
disk_status
这个函数的功能是获取设备的状态,只有一个参数pdrv,表示物理编号。因暂时只使用了SD卡,因此除了SD卡返回正常状态,其它类型设备全部返回的是非正常状态。
/*-----------------------------------------------------------------------*/
/* Get Drive Status */
/*-----------------------------------------------------------------------*/DSTATUS disk_status (BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{DSTATUS stat;int result;switch (pdrv) {case DEV_SD :return SD_disk_status(pdrv);}return STA_NOINIT;
}
disk_initialize
disk_initialize函数是设备初始化接口,也是有一个参数pdrv,用来指定设备物理编号。因只有一个SD设备,除了SD状态中调用了SD_Init()对SD卡进行了初始化设置,其它类型全部返回了未初始化。
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
/*-----------------------------------------------------------------------*/DSTATUS disk_initialize (BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{DSTATUS stat;int result;switch (pdrv) {case DEV_SD :return SD_disk_initialize(pdrv);}return STA_NOINIT;
}
disk_read
disk_read函数有四个形参。pdrv为设备物理编号。buff是一个BYTE类型指针变量,buff指向用来存放读取到数据的存储区首地址。 sector是一个DWORD类型变量,指定要读取数据的扇区首地址。count是一个UINT类型变量,指定扇区数量。
BYTE类型实际是unsigned char类型,DWORD类型实际是unsigned long类型, UINT类型实际是 unsigned int类型,类型定义在ff.h文件中。
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/DRESULT disk_read (BYTE pdrv, /* Physical drive nmuber to identify the drive */BYTE *buff, /* Data buffer to store read data */LBA_t sector, /* Start sector in LBA */UINT count /* Number of sectors to read */
)
{DRESULT res;int result;switch (pdrv) {case DEV_SD :return SD_disk_read(pdrv, buff, sector, count); }return RES_PARERR;
}
disk_write
disk_write函数有四个形参,pdrv为设备物理编号。buff指向待写入扇区数据的首地址。sector,指定要读取数据的扇区首地址。 count指定扇区数量
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/#if FF_FS_READONLY == 0DRESULT disk_write (BYTE pdrv, /* Physical drive nmuber to identify the drive */const BYTE *buff, /* Data to be written */LBA_t sector, /* Start sector in LBA */UINT count /* Number of sectors to write */
)
{DRESULT res;int result;switch (pdrv) {case DEV_SD :return SD_disk_write(pdrv, buff, sector, count); }return RES_PARERR;
}#endif
disk_ioctl
disk_ioctl函数有三个形参,pdrv为设备物理编号,cmd为控制指令,包括发出同步信号、获取扇区数目、获取扇区大小、 获取擦除块数量等等指令,buff为指令对应的数据指针。
对于SD卡,为支持格式化功能,需要用到获取扇区数量(GET_SECTOR_COUNT)指令和获取块尺寸(GET_BLOCK_SIZE)。另外,SD卡扇区大小为512字节, 串行Flash芯片一般设置扇区大小为4096字节,所以需要用到获取扇区大小(GET_SECTOR_SIZE)指令。
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/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_SD :return SD_disk_ioctl(pdrv, cmd, buff);;}return RES_PARERR;
}
配置ffconf.h
文件
#define FF_USE_MKFS 1
#define FF_CODE_PAGE 936
#define FF_USE_LFN 1
#define FF_VOLUMES 1
#define FF_MIN_SS 512
#define FF_MAX_SS 4096
-
FF_USE_MKFS: 格式化功能选择,为使用FatFs格式化功能,需要把它设置为1。
-
FF_CODE_PAGE: 语言功能选择,并要求把相关语言文件添加到工程宏。为支持简体中文文件名需要使用"936"
-
FF_USE_LFN: 长文件名支持,默认不支持长文件名,这里配置为1,支持长文件名,并指定将文件名存储在BSS段(数据段),也就是将其作为全局变量进行存储;配置为“#define FF_USE_LFN 2”就是将 文件名存储在STACK区(栈区);配置为“#define FF_USE_LFN 3”就是将文件名存储在HEAP(堆区)。一般配置为配置为“#define FF_USE_LFN 1”。如果存储在栈空间,防止某处操作不当而溢出。
-
FF_VOLUMES: 指定物理设备数量,这里设置为1,SD卡设备
-
FF_MIN_SS 、FF_MAX_SS: 指定扇区大小的最小值和最大值。SD卡扇区大小一般都为512字节,W25Q64芯片扇区大小一般设置为4096字节,所以需要把_MAX_SS改为4096。
测试代码
变量定义
FATFS fs;
FATFS *pfs;
FIL fp;
FRESULT fres;
DWORD fre_clust;
uint32_t totalSpace, freeSpace;
初始化部分
FRESULT ret = f_mount(&fs, "0:", 0x01);log_d("f_mount result: %02X\r\n", ret);if(ret != FR_OK){log_d("f_mount failed\r\n");Error_Handler();}/* Check freeSpace space */if(f_getfree("", &fre_clust, &pfs) != FR_OK){log_d("f_getfree failed\r\n");Error_Handler();}totalSpace = (uint32_t)((pfs->n_fatent - 2) * pfs->csize * 0.5);freeSpace = (uint32_t)(fre_clust * pfs->csize * 0.5);log_d("total:%dKB, free:%dKB\r\n", totalSpace, freeSpace);/* free space is less than 1kb */if(freeSpace < 1){log_d("freeSpace not enough\r\n");Error_Handler();}/* Open file to write */log_d("f_open first.txt\r\n");if(f_open(&fp, "first.txt", FA_OPEN_ALWAYS | FA_READ | FA_WRITE) != FR_OK){log_d("f_open failed\r\n");Error_Handler();}/* Writing text */f_puts("STM32 SD Card I/O Example via SPI\n", &fp);f_puts("Black Sheep Wall!!!", &fp);/* Close file */log_d("f_close first.txt\r\n");if(f_close(&fp) != FR_OK){log_d("f_close failed\r\n");Error_Handler();}/* Open file to read */log_d("f_open first.txt\r\n");if(f_open(&fp, "first.txt", FA_READ) != FR_OK){log_d("f_open failed\r\n");Error_Handler();}log_d("f_gets first.txt\r\n");while(f_gets(buffer, sizeof(buffer), &fp)){/* SWV output */log_d("%s", buffer);fflush(stdout);}log_d("\r\ndone\r\n");/* Close file */log_d("f_close first.txt\r\n");if(f_close(&fp) != FR_OK){log_d("f_close failed\r\n");Error_Handler();}/* Unmount SDCARD */log_d("f_mount unmount");if(f_mount(NULL, "0:", 1) != FR_OK) {log_d("f_mount failed (unmount)\r\n");Error_Handler();}
运行效果