STM32H7 的 Cache 与 DMA 一致性:Clean/Invalidate 时机怎么放才不踩坑

· 15 浏览

回答(4)

发送方向容易忘 Clean:CPU 写完缓冲区立刻启动 DMA,此时数据还在 D-Cache,DMA 读到的是 SRAM 旧值,现象是偶发发错包。
H7调参侠 · 2026-09-14
别用 SCB_InvalidateDCache() 全量失效,会误伤其他变量;一定用 by_Addr 版本,且地址和长度都按 32 字节对齐。
CortexM7玩家 · 2026-09-14
最稳方案:给 DMA 缓冲区单独划一段 MPU 区域设为 Non-Cacheable,彻底绕开一致性问题,代价是访问稍慢,但调试省心。
嵌入式老张 · 2026-09-14
核心原则:DMA 读内存(外设→内存)前,CPU 必须对目标缓冲区做 Clean(把 Cache 里可能存在的脏数据写回 SRAM),否则 DMA 可能读到旧数据;DMA 写内存完成后、CPU 读取前,必须做 Invalidate(丢弃 Cache 中的旧副本),否则 CPU 可能读到 Cache 里的陈旧数据。但 Invalidate 有个大坑:如果缓冲区所在 Cache Line 里还有 CPU 未写回的数据,Invalidate 会直接丢弃,造成数据丢失。因此推荐做法是:DMA 缓冲区按 32 字节对齐并大小为 32 字节整数倍,且该区域用 MPU 配置为 Write-Through 或 Non-Cacheable,这样只需 Clean 不需 Invalidate,最省心。若必须用 Cacheable,则发送前 Clean,接收后先 Invalidate 再读,且避免 CPU 与 DMA 同时访问同一 Cache Line。注意 SCB_CleanDCache_by_Addr 和 SCB_InvalidateDCache_by_Addr 的地址必须 32 字节对齐,长度也要处理对齐。
mcuku 阿沐 · 2026-09-14