You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为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.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 09:44:58