STM32H7 的 D-Cache 开启后 DMA 接收数据出现随机错误:地址对齐与 clean/invalidate 时序怎么排?

· 3 浏览

回答(4)

如果用的是 STM32H7 的以太网或 USB DMA,注意它们可能不支持非对齐访问,除了缓存行对齐,还要保证外设描述符本身 4 字节对齐,否则错误更隐蔽。
H7调参侠 · 2026-09-21
补充一个坑:invalidate 前一定要先 clean,否则会把 CPU 刚写但未回写的脏数据直接丢掉;另外地址和长度都要 32 字节对齐,否则 HAL 的 SCB 函数会按整行操作,误伤相邻变量。
CortexM7玩家 · 2026-09-21
最省心的做法:把 DMA 缓冲区放到 MPU 配置为 Non-cacheable 的 SRAM 区域,彻底不用 clean/invalidate,代价是 CPU 访问稍慢,但调试期能排除 90% 随机错误。
嵌入式老张 · 2026-09-21
STM32H7 的 D-Cache 与 DMA 共存时,核心矛盾是缓存一致性和对齐。首先,DMA 缓冲区必须按 32 字节对齐(Cortex-M7 缓存行大小),推荐用 `__attribute__((aligned(32)))` 或 `ALIGN_32` 定义,且长度最好为 32 的整数倍,避免同一缓存行被 CPU 和 DMA 同时访问导致数据撕裂。其次,时序要分方向:DMA 接收(外设到内存)前,若 CPU 之前写过该缓冲区,必须先 `SCB_CleanDCache_by_Addr` 把脏数据写回内存,否则 DMA 覆盖后缓存里仍是旧值;DMA 接收完成后,再 `SCB_InvalidateDCache_by_Addr` 丢弃缓存中可能被预取的旧行,让 CPU 读到 DMA 新数据。注意 invalidate 会丢弃未写回数据,所以接收前 clean 是必须的。发送方向则相反:DMA 发送前 clean,发送后无需 invalidate。若使用带 MPU 配置的 non-cacheable 区域,可彻底规避,但会牺牲性能。实操中建议把 DMA 缓冲区放在 D2 SRAM 并配置 MPU 为 write-through 或 non-cacheable,或严格按上述 clean/invalidate 顺序并保证 32 字节对齐。
mcuku 阿沐 · 2026-09-21