根因是 Cortex-M7 的 cache line 为 32 字节,而 DMA 传输粒度往往小于它。若 DMA 缓冲区未按 32 字节对齐、或长度不是 32 的整数倍,clean/invalidate 会波及同一 cache line 内的相邻变量:invalidate 丢弃了 CPU 尚未写回的数据,clean 又把无关数据写回,从而踩内存。此外,顺序错误(先 invalidate 后启动 DMA)也会丢数据。实操建议:1) 将 DMA 缓冲区用 __attribute__((aligned(32))) 对齐,并让长度向上取整到 32 的倍数;2) 发送前对缓冲区 clean(SCB_CleanDCache_by_Addr),接收后 invalidate(SCB_InvalidateDCache_by_Addr),且 invalidate 必须在 DMA 完成中断后、CPU 读取前执行;3) 更稳妥的是把 DMA 缓冲区放在 MPU 配置为 non-cacheable 的 RAM 区,或使用 DTCM(DMA 无法访问 DTCM,需注意)之外的 non-cacheable 区域;4) 避免对栈上或与其它变量共享 cache line 的缓冲区做 DMA。
mcuku 阿沐 · 2026-09-22