[STM32U5] 开启数据缓存后 FATFS 的 f_open 失败

[复制链接]
39|2
我在 main 函数里开启 D-Cache:
/* Enable D-Cache---------------------------------------------------------*/
SCB_EnableDCache();
我认为需要取消`sd_diskio.c`第 63 行注释,启用缓存维护宏:
/* USER CODE BEGIN enableSDDmaCacheMaintenance */
#define ENABLE_SD_DMA_CACHE_MAINTENANCE 1
/* USER CODE END enableSDDmaCacheMaintenance */
开启后,通过 DMA 从 SD 卡读取完成后会执行下面这段缓存失效代码:
#if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
/*
the SCB_InvalidateDCache_by_Addr() requires a 32-Byte aligned address,
adjust the address and the D-Cache size to invalidate accordingly.
*/
alignedAddr = (uint32_t)buff & ~0x1F;
SCB_InvalidateDCache_by_Addr((uint32_t*)alignedAddr, count*BLOCKSIZE + ((uint32_t)buff - alignedAddr));
我发现:虽然我给 FATFS 分配的缓冲区本身是 32 字节对齐的,但缓冲区传到`sd_diskio.c`这个函数的时候,地址不再保持对齐。
FATFS 内部会占用缓冲区前面若干字节,缓存失效操作会覆盖这部分前置字节,最终导致`f_open`调用失败。
我在`sd_diskio.c`大约 216 行、DMA 配置代码前面增加两行代码修复该问题:
alignedAddr = (uint32_t)buff & ~0x1F;
SCB_CleanDCache_by_Addr((uint32_t*)alignedAddr, ((uint32_t)buff - alignedAddr));
位置就在`BSP_SD_ReadBlocks_DMA`调用之前:
if(BSP_SD_ReadBlocks_DMA((uint32_t*)buff,
(uint32_t) (sector),
count) == MSD_OK)
我还没有进行完整验证,有可能其他位置也有同样问题。



又见江南雨 发表于 2026-9-3 13:33 | 显示全部楼层
你修复前的问题本质是缓存失效操作刷掉FATFS内部元数据,不是文件系统代码的错,是你的DMA缓冲区地址和FATFS工作区地址重叠了。
spicy 发表于 2026-9-3 13:44 | 显示全部楼层
根本解决之道是放弃在sd_diskio.c里做地址运算,改用HAL_SD_ReadBlocks_DSB方式,在DMA完成回调里直接用DSB指令同步数据,比SCB函数更底层也更可控。
才没有脸红 发表于 2026-9-3 15:10 | 显示全部楼层
真正根因在FATFS的f_open会先读取目录项,这个操作用的缓冲区不是用户传给读函数的那个,而是FS结构体内部的临时缓冲,你根本不知道它放在哪里。
故里说长安 发表于 2026-9-3 17:27 | 显示全部楼层
你在DMA读之前加Clean操作只能解决写回问题,但你这个场景是读操作,应该只需要Invalidate,你加Clean反而多刷了一次缓存,性能变差但恰好把数据对齐问题掩盖了。
没有太阳的晴天 发表于 2026-9-3 20:10 | 显示全部楼层
社区里ST官方建议不要在FATFS层做缓存维护,而是在SD底层驱动里把DMA缓冲区单独分配成32字节对齐且大小至少为单次传输块大小的两倍。
海滨消消 发表于 2026-9-3 22:46 | 显示全部楼层
你发现缓冲区传到sd_diskio.c时地址不再对齐,说明FATFS在你传入指针之前已经在该地址前面写了它自己的扇区缓存控制块,这是FATFS内部的内存管理策略,改不了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

193

主题

196

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部
0