如何为FatFS文件系统使用RAM缓冲区?挂载遇FR_NO_FILESYSTEM错误
我正在尝试使用Elm-chan的FatFS代码,最终要移植到微控制器实现SD卡文件读写。目前在PC上搭建环境,用动态RAM缓冲区模拟文件系统,代码能编译运行,但挂载时始终返回错误13:FR_NO_FILESYSTEM。
我知道格式化后的SD卡不需要f_mkfs(),但想理解它的用法。请问FatFS能否用RAM缓冲区作为卷/文件系统?如果可以,我的实现哪里错了?
我的ffconf.h和默认配置的差异:
#define FF_USE_MKFS 1 #define FF_CODE_PAGE 437
另外,我的实现中FF_MIN_SS = FF_MAX_SS = 512。
实现代码
diskio.c
#include <stdint.h> #include <stdio.h> #include "diskio.h" #include "ff.h" #include <stdlib.h> #include <string.h> static DSTATUS gStatus = STA_NOINIT; static BYTE *disk = NULL; #define NUM_SECTORS 128 DSTATUS disk_initialize( BYTE pdrv ) { if (pdrv == 0) { if (disk == NULL) { disk = malloc(FF_MIN_SS * NUM_SECTORS); if (disk != NULL) { // 清除未初始化标记 gStatus &= ~STA_NOINIT; // 将缓冲区清零 memset(disk, 0, FF_MIN_SS * NUM_SECTORS); } else { gStatus = STA_NOINIT; } } } return gStatus; } DSTATUS disk_status( BYTE drv ) { return gStatus; } DRESULT disk_read( BYTE pdrv, BYTE *buff, LBA_t sector, UINT count ) { DRESULT res = RES_OK; if (pdrv == 0 && sector <= NUM_SECTORS) { memcpy(buff, disk + (sector * FF_MIN_SS), count * FF_MIN_SS); } else { res = RES_PARERR; } return res; } DRESULT disk_write( BYTE pdrv, const BYTE *buff, LBA_t sector, UINT count ) { DRESULT res = RES_OK; if (pdrv == 0 && sector <= NUM_SECTORS) { memcpy(disk + (sector * FF_MIN_SS), buff, count * FF_MIN_SS); } else { res = RES_PARERR; } return res; } DRESULT disk_ioctl ( BYTE pdrv, /* [IN] 驱动器编号 */ BYTE cmd, /* [IN] 控制命令码 */ void* buff /* [I/O] 参数与数据缓冲区 */ ) { DRESULT res = RES_OK; if (pdrv != 0) { res = RES_PARERR; } else { switch(cmd) { case GET_SECTOR_COUNT: *(DWORD *)buff = NUM_SECTORS; res = RES_OK; break; case GET_BLOCK_SIZE: *(DWORD *)buff = 128; res = RES_OK; break; case CTRL_SYNC: res = RES_OK; break; default: res = RES_PARERR; break; } } return res; } DWORD get_fattime( void ) { // 返回0表示时间戳无效,这里不需要精确时间 return 0; }
main.c
#include <stdio.h> #include "ff.h" int main(void) { FATFS fs; FRESULT fres; FIL file; char *writeBuf = "Hello, World!"; unsigned int bytesWritten; BYTE work[FF_MIN_SS]; MKFS_PARM parm; parm.fmt = FM_FAT | FM_SFD; fres = f_mkfs("", &parm, work, sizeof(work)); if (fres != FR_OK) { printf("f_mkfs() failed: %d\r\n", fres); return -1; } fres = f_mount(&fs, "", 1); if (fres != FR_OK) { printf("f_mount() failed: %d\r\n", fres); return -1; } fres = f_open(&file, "test.txt", FA_CREATE_NEW | FA_WRITE); if (fres != FR_OK) { printf("f_open() failed: %d\r\n", fres); return -1; } return 0; }
运行情况
运行输出:f_mount() failed: 13
预期结果:成功将文件写入RAM缓冲区
1. 扇区读写的边界判断错误
disk_read和disk_write中的合法扇区判断逻辑错误:扇区编号从0开始,总扇区数为NUM_SECTORS时,合法的连续扇区范围应该是sector + count <= NUM_SECTORS(确保读写的所有扇区都不超出缓冲区),而非单个扇区sector <= NUM_SECTORS。
修复后的disk_read:
DRESULT disk_read( BYTE pdrv, BYTE *buff, LBA_t sector, UINT count ) { DRESULT res = RES_OK; if (pdrv == 0 && (sector + count) <= NUM_SECTORS) { memcpy(buff, disk + (sector * FF_MIN_SS), count * FF_MIN_SS); } else { res = RES_PARERR; } return res; }
disk_write做同样修改:
DRESULT disk_write( BYTE pdrv, const BYTE *buff, LBA_t sector, UINT count ) { DRESULT res = RES_OK; if (pdrv == 0 && (sector + count) <= NUM_SECTORS) { memcpy(disk + (sector * FF_MIN_SS), buff, count * FF_MIN_SS); } else { res = RES_PARERR; } return res; }
2. 磁盘块大小配置错误
disk_ioctl中GET_BLOCK_SIZE返回值设置为128,这是针对Flash等需要按块擦除的介质的参数。对于RAM磁盘,块大小应设为1(RAM可直接按扇区操作),错误的块大小会导致FatFS计算文件系统结构时出错,进而挂载失败。
修改disk_ioctl对应分支:
case GET_BLOCK_SIZE: *(DWORD *)buff = 1; // RAM磁盘按扇区操作,块大小为1个扇区 res = RES_OK; break;
3. 显式初始化磁盘缓冲区
在main开头显式调用disk_initialize(0),确保RAM缓冲区在f_mkfs前完成分配和清零:
int main(void) { FATFS fs; FRESULT fres; FIL file; char *writeBuf = "Hello, World!"; unsigned int bytesWritten; BYTE work[FF_MIN_SS]; MKFS_PARM parm; parm.fmt = FM_FAT | FM_SFD; // 显式初始化磁盘 disk_initialize(0); fres = f_mkfs("", &parm, work, sizeof(work)); // ... 后续代码不变 }
完成以上修改后,f_mkfs会正确在RAM缓冲区创建FAT文件系统,f_mount可成功挂载,后续的文件创建操作也能正常执行。
内容的提问来源于stack exchange,提问作者David V.

