目录
一、简介
FatFs是免费,开源的轻量级 文件系统,纯c实现,移植简单
二、源码下载
GitHub - abbrev/fatfs: FatFs - Generic FAT File System Module
三、移植条件
1、芯片参数
note:如遇挂载的失败,裸机请记得调整栈空间。
芯片类型:STM32F103VET6
flash大小为512KB,RAM大小 64KB
8GB大小SD卡。
本例中使用TFT屏幕自带SD卡硬件电路,使用SPI模式驱动SD卡
四、源码结构分析
用户移植适配的工作全部在diskio.c中完成。
五、配置文件重要参数说明
1、配置扇区大小
#define FF_MIN_SS 512
#define FF_MAX_SS 512
如果只需要挂载一个文件系统,以上两个值设置一样即可,本例中所用SD卡扇区大小为512,所以均设置为512。
如果需要挂载一个以上文件系统且两个设备扇区大小不同,以上两值设置范围要涵盖多个设备扇区范围。disk_ioctl接口需要提供GET_SECTOR_SIZE接口。
2、配置逻辑设备个数
(本例中使用DEV_MMC, 所以设备数配置为2, 盘符使用 1: 盘符)
#define FF_VOLUMES 2
3、配置格式化文件系统接口
#define FF_USE_MKFS 1
该字段配置为1,可以使用f_mkfs接口来格式化空白SD卡
六、diskio.c代码适配
note:留意下各个接口返回值,小心返回错误。
1、disk_status接口
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat = RES_OK;
switch (pdrv) {
case DEV_MMC :
stat = STA_NOINIT;
stat &= ~STA_NOINIT;
// translate the reslut code here
return stat;
}
return STA_NOINIT;
}
2、disk_initialize接口
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat = RES_OK;
int result;
switch (pdrv) {
case DEV_MMC :
result = b_sd_init();
if(result)
{
b_sd_set_speed(SPI_BAUDRATEPRESCALER_256);
b_sd_read_write_byte(0XFF);
b_sd_set_speed(SPI_BAUDRATEPRESCALER_2);
}
// translate the reslut code here
return stat;
}
return STA_NOINIT;
}
b_sd_init 为sd卡初始化接口、b_sd_set_speed 为设置spi速度接口、b_sd_read_write_byte 为spi读写单个字节接口,均会在下文给出。
3、disk_read接口
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 = RES_OK;
int ret;
switch (pdrv) {
case DEV_MMC :
// translate the arguments here
ret = b_sd_read_sector(sector, count, buff, 0XFF);
if(ret != 0)
{
res = RES_ERROR;
}
// translate the reslut code here
return res;
}
return RES_PARERR;
}
b_sd_read_sector 为sd卡的读扇区数据接口,会在下文给出。
4、disk_write接口
DRESULT 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 = RES_OK;
int ret;
switch (pdrv) {
case DEV_MMC :
// translate the arguments here
b_sd_set_speed(SPI_BAUDRATEPRESCALER_256);
ret = b_sd_write_sector(sector, count, (u8*)buff, 0XFF);
b_sd_set_speed(SPI_BAUDRATEPRESCALER_2);
if(ret != 0)
{
res = RES_ERROR;
}
// translate the reslut code here
return res;
}
return RES_PARERR;
}
b_sd_write_sector 为sd卡写扇区数据接口,会在下文给出。
5、disk_ioctl接口
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;
switch (pdrv) {
case DEV_MMC :
// Process of the command for the MMC/SD card
switch(cmd)
{
case CTRL_SYNC :
{
b_sd_sync_data();
res = RES_OK;
}
break;
case CTRL_TRIM:
{
res = RES_OK;
}break;
case GET_SECTOR_COUNT:
{
*(int*)buff = b_sd_get_sector_number();
}break;
case GET_SECTOR_SIZE:
{
*(int*)buff = b_sd_get_sector_size();
}break;
case GET_BLOCK_SIZE:
{
//*(int*)buff = b_sd_get_block_size();
*(int*)buff = 8;
}break;
}
return res;
}
return RES_PARERR;
}
b_sd_get_sector_number 为获取sd卡扇区个数接口,b_sd_get_sector_size为获取sd卡获取扇区大小(512字节接口),会在下文给出。
七、SD卡驱动实现
sd卡驱动实现请参考:
stm32读写SD卡(SPI模式)_spi sd卡_BIN-XYB的博客-优快云博客
或
八、用户Demo
note:s32\u32\u16\u8等为自定义实现,如报错,请按需修改
1、挂载设备
#include "ff.h"
#define DISK_SD "1:"
static int phase1_sd_fs_init(void)
{
static FATFS sd_fs;
u32 ret = 0;
MKFS_PARM opt = {0};
opt.fmt = FM_FAT;
static u8 work_buf[512] = {0};
ret = f_mount(&sd_fs, DISK_SD, 1);
if(ret != FR_OK)
{
switch(ret)
{
case FR_NO_FILESYSTEM:
{
ret = f_mkfs(DISK_SD, &opt, work_buf, sizeof(work_buf));
}break;
case FR_MKFS_ABORTED:
{
ret = f_mkfs(DISK_SD, &opt, work_buf, sizeof(work_buf));
}break;
}
}
if(ret != 0)
{
LOG_ERROR("sd fs f_mkfs fail(%d)\r\n", ret);
}
else
{
LOG_INFO("sd fs f_mkfs succ\r\n");
}
return ret;
}
2、文件操作
#define USER_FILE_NAME "1:/data.txt"
s32 b_demo_user_fs(void)
{
FIL fp;
u32 real_write_num = 0;
FRESULT ret = f_open(&fp, USER_FILE_NAME, FA_CREATE_ALWAYS | FA_WRITE | FA_READ);
if(ret != FR_OK)
{
LOG_ERROR("f_open fail:%s\r\n", USER_FILE_NAME);
return -1;
}
u8 *test_w_b = "fs test write data";
ret = f_write(&fp, test_w_b, strlen(test_w_b), &real_write_num);
if(ret != FR_OK)
{
LOG_ERROR("f_open fail:%d\r\n", ret );
return -1;
}
LOG_INFO("write len:%d\r\n", real_write_num);
LOG_INFO("write data:%s\r\n", test_w_b);
ret = f_close(&fp);
if(ret != FR_OK)
{
LOG_ERROR("f_close fail:%d\r\n", ret);
return -1;
}
u32 real_read_num = 0;
u8 test_r_b[100] = {0};
ret = f_open(&fp, USER_FILE_NAME, FA_READ);
if(ret != FR_OK)
{
LOG_ERROR("f_open fail:%s\r\n", USER_FILE_NAME);
return -1;
}
ret = f_read(&fp, test_r_b, 100, &real_read_num);
if(ret != FR_OK)
{
LOG_ERROR("f_read fail:%d\r\n", ret);
return -1;
}
LOG_INFO("read len:%d\r\n", real_read_num);
LOG_INFO("read data:%s\r\n", test_r_b);
ret = f_close(&fp);
if(ret != FR_OK)
{
LOG_ERROR("f_close fail:%d\r\n", ret);
return -1;
}
return 0;
}
3、运行截图