STM32H7 的 D-Cache 与 DMA 数据一致性:按行清理/无效化为什么仍会踩内存

· 3 浏览

回答(4)

如果数据量小且频繁,直接给该 RAM 区配 MPU 为 non-cacheable,省去 clean/invalidate 的时序烦恼,代价是访问稍慢。
RTOS搬砖工 · 2026-09-22
注意 SCB_InvalidateDCache_by_Addr 的地址参数必须是 32 字节对齐,长度也要按 32 对齐,否则 HAL 内部会做对齐扩展,反而扩大影响范围。
CortexM7玩家 · 2026-09-22
最简单可靠:把 DMA 缓冲区单独放一个段,用链接脚本对齐到 32 字节,并确保该段内只有 DMA 数据,不与其他变量混用。
嵌入式老张 · 2026-09-22
根因是 Cortex-M7 的 cache line 为 32 字节,而 DMA 传输粒度往往小于它。若 DMA 缓冲区未按 32 字节对齐、或长度不是 32 的整数倍,clean/invalidate 会波及同一 cache line 内的相邻变量:invalidate 丢弃了 CPU 尚未写回的数据,clean 又把无关数据写回,从而踩内存。此外,顺序错误(先 invalidate 后启动 DMA)也会丢数据。实操建议:1) 将 DMA 缓冲区用 __attribute__((aligned(32))) 对齐,并让长度向上取整到 32 的倍数;2) 发送前对缓冲区 clean(SCB_CleanDCache_by_Addr),接收后 invalidate(SCB_InvalidateDCache_by_Addr),且 invalidate 必须在 DMA 完成中断后、CPU 读取前执行;3) 更稳妥的是把 DMA 缓冲区放在 MPU 配置为 non-cacheable 的 RAM 区,或使用 DTCM(DMA 无法访问 DTCM,需注意)之外的 non-cacheable 区域;4) 避免对栈上或与其它变量共享 cache line 的缓冲区做 DMA。
mcuku 阿沐 · 2026-09-22