STM32H7 的 Cache 与 DMA 数据一致性问题:Clean/Invalidate 的边界与踩坑复盘

· 22 浏览

回答(4)

注意DMA双缓冲模式:切换缓冲区时,CPU正在处理A缓冲,DMA写B缓冲,此时对B做Invalidate是安全的,但若CPU也读了B,就必须先Clean再Invalidate,顺序不能反。
DMA小王子 · 2026-09-20
更稳妥的方案:用MPU把DMA缓冲区配成Non-Cacheable,虽然损失一点性能,但省去所有Clean/Invalidate调用,代码简单且不易出错,适合对实时性要求不极端的场景。
H7踩坑人 · 2026-09-20
补充一个实测坑:H7的Cache行是32字节,但Clean/Invalidate函数内部按4字节对齐检查,若缓冲区首地址未32字节对齐,会多清相邻数据,导致其他变量被意外写回或丢弃。
嵌入式老白 · 2026-09-20
STM32H7的D-Cache与DMA一致性核心在于:DMA访问的是物理内存,而CPU可能读写Cache中的副本。正确做法:发送方向(CPU写→DMA读),在启动DMA前对缓冲区执行Clean(写回)操作,确保数据落到SRAM;接收方向(DMA写→CPU读),在DMA完成后再对缓冲区执行Invalidate(无效化),丢弃Cache中可能存在的旧数据。边界坑点:1)Clean/Invalidate必须按Cache行(32字节)对齐,长度向上取整,否则会误伤相邻变量;2)Invalidate前若CPU已读过该区域,Cache中可能有脏数据,直接Invalidate会丢失未写回内容,应先Clean再Invalidate;3)DMA传输期间CPU不要访问该缓冲区,否则Cache可能重新填充;4)使用SCB_CleanDCache_by_Addr等CMSIS函数,注意地址需32字节对齐。推荐将DMA缓冲区放在非Cache区域(MPU配置为Device或Write-Through),或使用__attribute__((section(".dma_buffer")))并配合MPU,可彻底避免一致性问题。
mcuku 阿沐 · 2026-09-20