STM32H7 的 Cache 与 DMA 数据一致性:Clean/Invalidate 的时机与典型踩坑

· 5 浏览

回答(4)

调试时可在 Clean/Invalidate 前后加内存屏障 __DSB(),防止编译器或流水线重排导致时序错乱。
裸机小王子 · 2026-09-28
注意 SCB_InvalidateDCache_by_Addr 的地址和长度都要 32 字节对齐,否则 HAL 内部会按行处理,可能误伤相邻数据。
Cortex_M7 · 2026-09-28
最省心的做法:把 DMA 缓冲区放到 DTCM 或 MPU 配成 Non-Cacheable,直接免掉 Clean/Invalidate,代价是 CPU 访问稍慢,但逻辑最稳。
嵌入式老张 · 2026-09-28
STM32H7 的 D-Cache 与 DMA 一致性核心原则:CPU 写、DMA 读(发送)前,对源缓冲区做 Clean(写回),把 Cache 中脏数据刷到 SRAM;DMA 写、CPU 读(接收)前,对目标缓冲区做 Invalidate(无效化),丢弃 Cache 中旧副本,让 CPU 重新从 SRAM 读。典型踩坑:1) 缓冲区未按 Cache Line(H7 为 32 字节)对齐,Invalidate 会丢弃相邻变量,导致数据莫名被改;2) 接收时先 Invalidate 再启动 DMA,若 DMA 尚未完成就访问,读到旧数据;正确顺序是 DMA 完成中断后再 Invalidate;3) 发送时只 Clean 不等待,DMA 启动前 Cache 又写入新数据;4) 用 DTCM RAM 可绕过 Cache,但需确认 DMA 能否访问(MDMA 可,部分 DMA 不可)。实操建议:缓冲区用 __attribute__((aligned(32))) 并放在非 Cache 区或按行对齐;发送前 SCB_CleanDCache_by_Addr,接收后 SCB_InvalidateDCache_by_Addr;中断中避免频繁全 Cache 操作,必要时用 MPU 将 DMA 缓冲区配置为 Write-Through 或 Non-Cacheable。
mcuku 阿沐 · 2026-09-28