STM32H7 的 D-Cache 开启后 DMA 数据错乱:地址对齐与 clean/invalidate 的正确顺序实战

· 4 浏览

回答(4)

简单粗暴方案:把DMA buffer直接定义到DTCM RAM(0x20000000),DTCM不经过D-Cache,完全不用clean/invalidate,代价是DTCM只有128KB且CPU访问快但DMA带宽一般。
硬件阿飞 · 2026-09-24
实测踩坑:invalidate之后如果CPU马上读缓冲区,可能读到DMA还没写完的中间态。正确做法是等DMA传输完成中断后再invalidate,再读数据,顺序别搞反。
码农小陈 · 2026-09-24
补充一点:H7的AXI SRAM(0x24000000)默认是Cacheable的,很多人以为放这里就没事。若用MPU把该区域设为Non-Cacheable,记得同时配置Normal、Non-shareable属性,否则性能会掉。
嵌入式老张 · 2026-09-24
这是H7上最经典的坑:D-Cache开启后,CPU读写走Cache,DMA直接访问SRAM,两者不一致就会错乱。核心原则有三条。第一,DMA缓冲区必须32字节对齐(H7 Cache Line为32B),用__attribute__((aligned(32)))或ALIGN_32定义,且缓冲区大小补齐到32的整数倍,否则clean/invalidate会波及相邻变量。第二,方向决定操作:外设到内存(DMA接收)在启动DMA前先invalidate,防止Cache里的旧数据在DMA写完后被回写覆盖;内存到外设(DMA发送)在启动DMA前先clean,把CPU改过的数据刷到SRAM。第三,顺序不能反:接收场景若先clean再invalidate,或发送场景先invalidate,都会丢数据。推荐用SCB_InvalidateDCache_by_Addr和SCB_CleanDCache_by_Addr,传入地址需32字节对齐。更稳妥的做法是把DMA缓冲区放到MPU配置为Non-Cacheable的区域,或使用DTCM/SRAM4(0x30000000)等不被Cache的区域,从根上避免一致性问题。
mcuku 阿沐 · 2026-09-24