# 🧩 STM32H7 SDMMC 无 DMA 配置项、FatFs 无法挂载问题完整解析与解决方案
> 适用于 STM32CubeMX 6.9 / 6.10+
> 以及 STM32H7 系列 MCU(如 H743、H750、H725、H735 等)
## 一、问题现象
在 CubeMX 新版本中使用 **SDMMC1 + FatFs** 时,常出现以下问题:
- SDMMC1 配置界面完全没有 “DMA Settings” 选项;
- 工程生成后,`sd_diskio.c` 自动调用:
```c
BSP_SD_ReadBlocks_DMA();
- 实际运行时
f_mount()返回:FR_DISK_ERR (1) - 打印调试发现:
HAL_SD_ReadBlocks_DMA() 返回 HAL_ERROR挂载失败。
二、原因分析(来龙去脉)
这个问题并不是你的配置错误,而是 STM32H7 架构升级 + CubeMX 模板滞后 的组合结果。
🧠 1. 硬件层变化:STM32H7 引入内部 DMA(IDMA)
在早期的 STM32F4 / F7 系列中,SDIO/SDMMC 外设依赖 外部 DMA 控制器(DMA1、DMA2 或 BDMA):
SDMMC → 外部 DMA 控制器 → 内存
但自 STM32H7 开始,SDMMC 控制器集成了 内部 DMA 引擎 (IDMA),
数据传输路径变为:
SDMMC (带 IDMA) → 内存
这意味着:
- 不再需要外部 DMA;
- 不占用任何 BDMA/DMA 通道;
- 性能更高,硬件延迟更低。
📖 官方文档说明
STM32H743 Reference Manual (RM0433 Rev.9, Section 66.4.9)
“The SDMMC1 and SDMMC2 include an internal DMA (IDMA) to transfer data between memory and FIFO without using external DMA.”
—— ST 官方手册原文
因此,在 CubeMX 的 SDMMC1 配置界面中:
- “DMA Settings” 页被移除;
- 无需也不能手动添加 DMA 通道。
⚙️ 2. 软件模板滞后(FatFs 层未更新)
虽然硬件和 HAL 库都支持 IDMA,
但 CubeMX 的 FatFs 模板文件(sd_diskio.c / bsp_driver_sd.c) 仍使用旧时代的外部 DMA 写法:
res = BSP_SD_ReadBlocks_DMA(...);
而内部并没有外部 DMA 配置,因此:
HAL_SD_ReadBlocks_DMA()返回HAL_ERRORdisk_read()返回RES_ERRORf_mount()最终报FR_DISK_ERR (1)
三、CubeMX 为什么隐藏 DMA?
因为在 STM32H7 中,SDMMC 的 DMA 已经是内置的 IDMA,不再通过外部控制器配置。
所以:
- “System Core → BDMA / MDMA” 中手动添加通道是无效的;
- “SDMMC → Configuration → DMA Settings” 页面被彻底移除;
- ST 官方打算让用户直接使用 IDMA,而不是手动绑定外部 DMA。
目前 CubeMX 界面与 FatFs 模板还未完全同步,
所以出现了 “界面没有 DMA” + “代码仍调用外部 DMA” 的冲突。
四、解决方案
可以通过两种方式修复此问题。
✅ 方案一(推荐)—— 启用内部 IDMA
在代码中显式启用 Internal DMA (IDMA),即可正常工作。
🔧 修改步骤
1️⃣ 打开文件FATFS/Target/bsp_driver_sd.c
或Core/Src/sdmmc.c(具体路径视项目而定)
2️⃣ 在 HAL_SD_Init() 成功后添加如下代码:
/* Enable SDMMC Internal DMA (IDMA) */
if (HAL_SDEx_EnableIDMA(&hsd1) != HAL_OK)
{
printf("⚠️ Failed to enable SDMMC internal DMA!\r\n");
}
else
{
printf("✅ SDMMC internal DMA enabled.\r\n");
}
对于部分 HAL 版本,也可能叫:
HAL_SD_ConfigIDMARegion(&hsd1, 0);
3️⃣ 重新编译运行。
成功后串口输出应类似:
✅ SDMMC internal DMA enabled.
SD Card mount OK.
FAT type = 4
⚠️ 注意事项
- IDMA 不能访问 DTCM RAM(0x20000000 起始区域)
→ 请将 FatFs 缓冲区放在 AXI SRAM(0x24000000 起)或 SRAM1 区域。 - 保持 FatFs “Use DMA Template” 选项开启。
否则HAL_SD_ReadBlocks_DMA()不会被调用。 - HAL 库版本 ≥ 1.11 时默认支持 IDMA。
🧰 方案二(临时方案)—— 使用轮询模式
若只想验证功能,可以禁用 DMA 调用,改为阻塞方式。
1️⃣ 打开 sd_diskio.c
2️⃣ 修改以下行:
res = BSP_SD_ReadBlocks_DMA(...);
改为:
res = BSP_SD_ReadBlocks(...);
同理:
res = BSP_SD_WriteBlocks_DMA(...);
改为:
res = BSP_SD_WriteBlocks(...);
这样系统会使用普通读写模式,虽然速度稍慢,但能稳定挂载。
五、验证效果
成功后串口输出应如下:
==== SD Card Test Start ====
Calling BSP_SD_Init()...
BSP_SD_Init() returned 0
✅ SDMMC internal DMA enabled.
SD Init OK
SD Card mount OK.
FAT type = 4
Total space: 244198400 KB
六、总结表
| 项目 | 旧版 (F4/F7) | 新版 (H7) |
|---|---|---|
| DMA 模式 | 外部 DMA 控制器 (DMA1/BDMA) | 内置 IDMA |
| CubeMX 界面 | 可添加 DMA 通道 | 无 DMA 配置项 |
| FatFs 模板 | 使用外部 DMA | 模板未更新 |
| 默认结果 | HAL_SD_ReadBlocks_DMA() 失败 | 需手动启用 IDMA |
| 推荐方案 | Add DMA 通道 | 调用 HAL_SDEx_EnableIDMA() |
| 临时方案 | 轮询版读写 | 调用 BSP_SD_ReadBlocks() |
七、最终结论
STM32H7 的 SDMMC 外设自带内部 DMA (IDMA),不再需要外部 DMA。
CubeMX 因此不再显示 DMA 配置项,这是设计使然,不是 Bug。
但 FatFs 模板仍然沿用旧版外部 DMA 逻辑,
需要开发者在代码中手动调用:HAL_SDEx_EnableIDMA(&hsd1);来启用内部 DMA 引擎,
这样就能让 FatFs 成功挂载 SD 卡。
八、参考资料
- ST 官方手册:
RM0433 Rev.9 — STM32H743 Reference Manual, Section 66.4.9 “Internal DMA (IDMA)” - ST 官方社区讨论:
STM32H743 SDMMC DMA not configurable - ST 中文社区:
STM32H7 SDMMC 内置 DMA 的使用说明
九、附录:推荐 BSP_SD_Init() 示例
int BSP_SD_Init(void)
{
if (HAL_SD_Init(&hsd1) != HAL_OK)
{
printf("❌ HAL_SD_Init failed!\r\n");
return MSD_ERROR;
}
/* 启用 SDMMC 内部 DMA (IDMA) */
if (HAL_SDEx_EnableIDMA(&hsd1) != HAL_OK)
{
printf("⚠️ Failed to enable SDMMC internal DMA!\r\n");
}
else
{
printf("✅ SDMMC internal DMA enabled.\r\n");
}
/* 获取 SD 卡信息 */
HAL_SD_CardInfoTypeDef CardInfo;
HAL_SD_GetCardInfo(&hsd1, &CardInfo);
printf("SD Capacity: %.2f GB\r\n",
(float)(CardInfo.BlockNbr * CardInfo.BlockSize) / (1024 * 1024 * 1024));
return MSD_OK;
}
✅ 总结一句话:
- 你没配置错,CubeMX 也没坏;
- STM32H7 的 SDMMC 不再使用外部 DMA,而是内置 IDMA;
- 只需在初始化后加一句
HAL_SDEx_EnableIDMA(&hsd1);即可完美解决挂载失败问题。

Comments NOTHING