STM32H7 的 DCache 与 DMA 一致性:Clean/Invalidate 的边界条件与踩坑复盘

· 6 浏览

回答(4)

长度和地址都要 32 字节对齐,我踩过按字节长度 invalidate 把旁边标志位清掉的坑,建议缓冲区用 __attribute__((aligned(32)))。
H7搬砖人 · 2026-10-11
注意 SCB_InvalidateDCache_by_Addr 会丢弃未写回数据,只应在 DMA 写完成后、CPU 读之前调用,别在 DMA 进行中调用。
Cortex小马 · 2026-10-11
最稳做法是给 DMA 缓冲区单独划一段 MPU Non-cacheable 区域,彻底绕开 clean/invalidate,代价是 CPU 访问该区略慢,但省心。
嵌入式老张 · 2026-10-11
STM32H7 的 DCache 与 DMA 一致性核心在于:DMA 不经过 cache,CPU 访问可能命中脏行。发送方向(内存→外设):CPU 写完数据后必须 SCB_CleanDCache_by_Addr,把脏行写回 SRAM,再启动 DMA,否则 DMA 读到旧数据。接收方向(外设→内存):启动 DMA 前若该缓冲区可能被 cache 命中,应先 Invalidate;DMA 完成后必须再 Invalidate,且要在读取数据之前。边界条件:地址必须 32 字节对齐,长度按 32 字节向上取整,否则会误伤相邻变量。常见坑:1) 在 DMA 传输中途 Invalidate,导致未写回的数据丢失;2) 用 Clean+Invalidate 代替单纯 Invalidate,把 CPU 刚写的数据也清掉;3) 中断里先读数据再 Invalidate,读到脏行;4) 多缓冲区/描述符链未逐段维护。实操建议:把 DMA 缓冲区放到 MPU 配置为 Non-cacheable 的区段,或统一封装 cache 维护函数,在启动 DMA 前 Clean、完成中断里 Invalidate,并保证对齐。
mcuku 阿沐 · 2026-10-11