Fatfs文件系统
一般用在读写SD卡,u盘等
主要文件:
ff.c
ff.h
ffconf.h
diskio.h
ffsystem.c
ffunicode.c
必须实现diskio.c对应diskio.h文件
FatFs会调用:
disk_initialize()
disk_status()
disk_read()
disk_write()
disk_ioctl()
使用FatFs的基本流程
移植
复制FatFs核心
+ 配置ffconf.h
+ 实现diskio.c
+ 实现SD卡底层驱动
+ 实现get_fattime
+ 加入构建系统
+ 初始化并f_mount
完成这些以后,才可以直接调用:
f_open()
f_read()
f_write()
f_close()
f_mkfs()
Diskio.c
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module for FatFs - SD Card (SPI4) drive */
/* 盘0 = SD 卡 (SPI4 模式), 作为唯一 FatFs 卷 (存储相片/USB 导出) */
/*-----------------------------------------------------------------------*/
#include "ff.h"
#include "diskio.h" /* FatFs lower layer API */
#include "string.h"
#include "mh2457.h"
#include "sd_spi.h" /* SD_SPI_GetSectorCount */
#include "rtc_calendar.h" /* BSP RTC calendar / FAT timestamp */
#include <stdbool.h>
/* 物理盘编号:0 = SD 卡 */
#define SD_PDRV 0
/* U盘模式互斥:USB 挂载 PC 时 SD 卡 FAT 卷独占给 USB MSD,
* 拒绝一切设备侧读/写,防止本机与 PC 双写同一卷损坏 FAT、或任务上下文与
* USB ISR 重入 SPI 总线。USB 自身在 ISR 内持锁(s_usbSdLocked)时放行。
* 注意:此处跨层引用 usb_msd.c 的符号,用 extern 避免头路径耦合。
* (与参考工程 JW-MCU-TM30/BSP/Source/diskio.c 的实现一致) */
extern bool usb_msd_is_active(void);
extern bool usb_msd_sd_locked(void);
/* SPI4/SD transaction lock shared by task-side FatFs and USB IRQ callbacks.
* s_usbSdLocked only identifies the caller; it is not itself a lock. Without
* this guard USB1_IRQHandler could preempt an in-progress CMD17/CMD24 sequence
* and inject a second SD command into the same SPI transaction. */
static volatile bool s_sdIoBusy = false;
static bool sd_io_try_lock(void)
{
bool acquired = false;
uint32_t primask = __get_PRIMASK();
__disable_irq();
if (!s_sdIoBusy && (!usb_msd_is_active() || usb_msd_sd_locked())) {
s_sdIoBusy = true;
acquired = true;
}
__set_PRIMASK(primask);
return acquired;
}
static void sd_io_unlock(void)
{
uint32_t primask = __get_PRIMASK();
__disable_irq();
s_sdIoBusy = false;
__set_PRIMASK(primask);
}
/*-----------------------------------------------------------------------*/
/* 获取设备状态 */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status(
BYTE pdrv /* 物理编号 */
)
{
if (pdrv != SD_PDRV) {
return STA_NOINIT;
}
return SD_SPI_Status();
}
/*-----------------------------------------------------------------------*/
/* 设备初始化 */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize(
BYTE pdrv /* 物理编号 */
)
{
DSTATUS result;
if (pdrv != SD_PDRV) {
return STA_NOINIT;
}
/* SPI4 + GPIO + 电源已在 SD_SPI_Init() 中完成 (main 启动阶段调用)。
* 此处执行 SD 卡协议初始化。
*
* 与 disk_read/disk_write 共用同一把锁:SD 协议初始化同样是一段完整的
* 总线事务(CMD0..CMD9),U盘模式期间本机一律不得发起。不加锁的话,
* 安全性就只能依赖"调用它的时候 USB 恰好没在读"这种隐含前提。 */
if (!sd_io_try_lock()) {
return STA_NOINIT;
}
result = SD_SPI_Initialize();
sd_io_unlock();
return result;
}
/*-----------------------------------------------------------------------*/
/* 读扇区 */
/*-----------------------------------------------------------------------*/
DRESULT disk_read(
BYTE pdrv, /* 物理编号 */
BYTE* buff, /* 数据缓冲区 */
DWORD sector, /* 起始扇区 */
UINT count /* 扇区个数 */
)
{
if (pdrv != SD_PDRV || count == 0) {
return RES_PARERR;
}
/* 原子地完成所有权检查和 SPI 事务加锁;既阻止本机在 UMS 期间进入,
* 也阻止 USB IRQ 嵌套进已经开始的本机 SD 命令。 */
if (!sd_io_try_lock()) {
return RES_NOTRDY;
}
DRESULT result = SD_SPI_ReadSectors(buff, sector, count);
sd_io_unlock();
return result;
}
/*-----------------------------------------------------------------------*/
/* 写扇区 */
/*-----------------------------------------------------------------------*/
DRESULT disk_write(
BYTE pdrv, /* 物理编号 */
const BYTE* buff, /* 待写入数据 */
DWORD sector, /* 起始扇区 */
UINT count /* 扇区个数 */
)
{
if (pdrv != SD_PDRV || count == 0) {
return RES_PARERR;
}
if (!sd_io_try_lock()) {
return RES_NOTRDY;
}
DRESULT result = SD_SPI_WriteSectors(buff, sector, count);
sd_io_unlock();
return result;
}
/*-----------------------------------------------------------------------*/
/* 其他控制 */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl(
BYTE pdrv, /* 物理编号 */
BYTE cmd, /* 控制命令 */
void* buff /* 结果缓冲区 */
)
{
if (pdrv != SD_PDRV) {
return RES_PARERR;
}
switch (cmd) {
case GET_SECTOR_SIZE: /* 返回扇区大小 (固定 512) */
*(WORD*)buff = 512;
return RES_OK;
case GET_SECTOR_COUNT: /* 返回卡总扇区数 (CSD 解析) */
*(DWORD*)buff = SD_SPI_GetSectorCount();
return RES_OK;
case GET_BLOCK_SIZE: /* 返回擦除块大小(以扇区为单位) */
*(DWORD*)buff = 8; /* SD 卡典型 4KB/512B */
return RES_OK;
case CTRL_SYNC:
return RES_OK;
case CTRL_TRIM:
return RES_OK;
default:
return RES_PARERR;
}
}
/*-----------------------------------------------------------------------*/
/* 获取当前 RTC 日历时间 */
/*-----------------------------------------------------------------------*/
__WEAK DWORD get_fattime(void)
{
return (DWORD)RtcCalendar_GetFatTime();
}