You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

STM32F407VET使用FatFS时f_close返回FR_DISK_ERR问题求助

问题分析与解决方案

咱们先拆解下你遇到的几个矛盾现象,这能帮咱们定位问题根源:

  • 正常写入时f_write返回FR_OKf_closeFR_DISK_ERR,最终文件为空
  • 64KB分配单元+已有文本的文件,写入64KB后f_close仍报错,但数据能在Windows正常读取
  • 空文件写入后,即便f_write成功,最终还是空文件

核心原因定位

FatFS的f_write只是把数据写到了RAM中的文件缓存,真正的磁盘写入是在f_close(或f_sync)时触发的——它会把缓存里的数据刷到SD卡,同时更新目录项(比如文件大小、修改时间)。你遇到的问题本质是:底层SDIO写操作在触发最终同步时失败了,导致缓存数据没落地,或者目录项没更新。

为什么64KB分配单元的已有文件能保留数据?因为FatFS的缓存大小默认和分配单元(簇大小)匹配,当你写入的内容刚好填满一个缓存块时,FatFS会提前把缓存刷到SD卡,这部分数据已经落地了;但f_close时需要更新目录项,这一步的写入失败,所以还是返回FR_DISK_ERR。而空文件的情况,缓存没填满,只有f_close才会触发刷写,这一步失败就导致数据完全丢失。

具体排查&解决步骤

1. 先查底层SDIO驱动的写操作返回值

FR_DISK_ERR是FatFS调用底层disk_write函数时收到错误返回的,你要在disk_write实现里加日志,跟踪STM32 SDIO HAL库的HAL_SD_WriteBlocks返回值——很多时候看似写成功,实际是有超时、CRC错误或者SD卡响应异常。比如:

DRESULT disk_write (BYTE pdrv, const BYTE *buff, DWORD sector, UINT count)
{
  HAL_StatusTypeDef status = HAL_OK;
  status = HAL_SD_WriteBlocks(&hsd, (uint8_t*)buff, sector, count, 1000);
  // 这里加日志打印status的值,比如用串口输出
  if (status != HAL_OK) {
    // 记录具体错误码,比如HAL_TIMEOUT、HAL_ERROR等
    return RES_ERROR;
  }
  return RES_OK;
}

2. 调整FatFS的缓存配置

打开ffconf.h检查以下参数:

  • _MAX_SS:设置为SD卡实际的扇区大小(用HAL_SD_GetCardInfo可以获取,现在很多SD卡是4KB物理扇区,逻辑扇区可能还是512)
  • _USE_WRITE_BUFFER:如果开启了缓存,可以先试试关闭它(设置为0),强制f_write直接写入SD卡,虽然性能下降,但能排查是不是缓存同步的问题
  • _FS_TINY:确保没开启这个,小容量模式会限制缓存行为

3. 重新格式化SD卡(重点)

Windows自带的格式化工具有时候会有兼容性问题,尤其是大卡:

  • 用SanDisk官方的SD卡格式化工具,选择Fat32格式,分配单元大小设为64KB,关闭快速格式化
  • 不要用NTFS或exFAT,FatFS对这两个格式的支持有限(需要额外配置)

4. 降低SDIO时钟和总线宽度

STM32F407的SDIO默认时钟可能到48MHz,但Sandisk Ultra卡在某些硬件环境下(比如布线不好)写操作会不稳定:

  • 把SDIO时钟降到24MHz甚至12MHz(修改RCC配置里的SDIO分频系数)
  • 先把总线宽度从4位降到1位,排查是不是总线干扰导致的写入错误

5. 测试f_sync操作

f_close之前先调用f_sync(&file),看返回值:

  • 如果f_sync返回FR_DISK_ERR,那百分百是底层写操作的问题
  • 如果f_sync成功但f_close报错,那可能是更新目录项时出错,数据已经落地,但目录项没更新(这时候文件在Windows能看到,但FatFS下次读取可能识别不了)

6. 检查目录项的写入

空文件写入后需要更新目录项的文件大小等信息,如果目录项所在的扇区写入失败,就会导致文件显示为空。你可以试试先创建一个有内容的文件,再追加写入,看是不是目录项写入的问题。


内容的提问来源于stack exchange,提问作者Vijay Anand Chandrasekaran

火山引擎 最新活动