FatFs在小内存单片机上卡在f_mount返回FR_NOT_READY,根本原因是默认配置申请缓冲区远超RAM容量;需关闭长文件名、禁用exFAT、改用静态工作区缓冲,并确保FF_MAX_SS=512。

为什么 FatFs 在小内存单片机上常卡在 f_mount 返回 FR_NOT_READY
根本原因不是 SD 卡没插好,而是 FatFs 默认配置仍试图分配远超你 MCU RAM 容量的缓冲区。比如 STM32F103C8(20KB RAM)跑默认 FF_FS_EXFAT=0 + FF_USE_LFN=1 时,f_mount 会悄悄申请几百字节栈空间+动态堆缓冲,而你的 heap 可能根本没开,或只开了 2KB —— 这时它连磁盘状态都读不全,直接报 FR_NOT_READY。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 关闭长文件名:
FF_USE_LFN = 0(否则每个目录项额外吃 256 字节栈+缓存) - 禁用 exFAT:
FF_FS_EXFAT = 0(FAT32 足够,省掉大块扇区解析逻辑) - 把工作区缓冲挪到静态内存:定义全局数组
uint8_t g_work_buffer[FF_MAX_SS];,传给f_mount的第三个参数,别用NULL - 确认
FF_MAX_SS设为 512(SD 卡标准扇区大小),别误设成 4096
SDIO 或 SPI 模式下,f_open 失败返回 FR_DISK_ERR 怎么定位
这个错误本质是底层 disk_read/disk_write 函数出问题,和 FatFs 无关。SPI 模式下最常见的是 CS 电平没拉低、MOSI/MISO 时序错半拍;SDIO 模式则多因时钟分频没配对(比如 APB2=72MHz 时,SDIOCLK 分频后必须 ≥ 400kHz 初始化阶段,但 ≤ 25MHz 数据阶段)。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 先写个裸机函数发 0x00 到 SD 卡,用逻辑分析仪看 MOSI 是否真有输出、CS 是否按时拉低
- SPI 模式务必检查
disk_ioctl中CTRL_SYNC是否真的等待了 SPI 总线空闲(很多移植漏掉这步,导致后续命令乱序) - SDIO 模式下,初始化前调用
HAL_SD_InitCard后,立刻用HAL_SD_GetCardState看返回值,不是HAL_SD_CARD_READY就别进 FatFs -
f_open前加一句if (f_mount(&FatFs, "", 1) != FR_OK) while(1);,避免挂载失败还硬开文件
f_write 写入速度慢、中途卡死的三个硬件级原因
FatFs 层面的 f_write 慢,90% 是被底层拖住:要么 SPI 时钟太低(比如 100kHz),要么 SD 卡内部忙没检测(disk_ioctl 没实现 CTRL_POWER 或 CTRL_STATUS),要么扇区写未对齐(向非 512 字节边界地址写,触发 FatFs 隐式读-改-写流程,小内存设备直接爆栈)。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- SPI 时钟至少设到 4MHz(STM32 HAL 库里
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;) -
disk_ioctl必须响应CTRL_STATUS:返回STA_NOINIT/STA_NODISK/STA_PROTECT,否则 FatFs 以为卡一直就绪,狂发命令 - 所有
f_write的buff地址和size必须是 512 字节对齐——用__align(512) uint8_t tx_buf[512];声明缓冲区,别用 malloc - 别在中断里调用
f_write,SD 卡操作全程阻塞,中断里调用等于锁死整个系统
如何让 f_printf 在无 stdio 的环境下工作
默认 f_printf 依赖 libc 的 vprintf,而小内存单片机往往禁用 newlib-nano 或没链接 printf 相关.o。强行开启会导致代码体积暴涨、RAM 不够。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 关闭
FF_USE_STRFUNC(设为 0),彻底不用f_printf,改用f_write+ 手动itoa拼接字符串 - 若真需要格式化,自己实现极简版:
void my_fprintf(FIL* fp, const char* fmt, ...),只支持%d和%s,用vsprintf重定向到 64 字节栈缓冲,再f_write出去 - 注意:FatFs 的
f_puts是安全的,它只是封装了f_write,可放心用
最麻烦的从来不是 FatFs 本身,而是你忘了 SD 卡上电后要等至少 1ms 才能发 CMD0,或者 SPI 的 CPOL/CPHA 配成了 0/1 而 SD 卡只认 0/0 —— 这些细节不会报错,只会让你对着 FR_TIMEOUT 发呆一整天。



















