这类偶发错位几乎都源于把 Clean 和 Invalidate 当成了可互换操作。正确原则:CPU 写缓冲区后交给 DMA 发送,只需 Clean(把脏行写回内存),绝不能 Invalidate,否则会丢弃尚未回写的 CPU 数据;DMA 接收完成后交给 CPU 读取,必须先 Invalidate 再读,且 Invalidate 前要确保 DMA 已停止或已通过中断/标志确认传输完成,否则会把 DMA 刚写入但未命中的行清掉。排查时先确认缓冲区按 32 字节对齐(H7 Cache 行 32B),长度向上取整到行边界,避免相邻变量被误清。再用 SCB_CleanDCache_by_Addr / SCB_InvalidateDCache_by_Addr 替代整片 Clean/Invalidate,缩小影响范围。双缓冲切换时在 DMA 完成中断里先 Invalidated 当前读缓冲,再切换;发送侧在启动 DMA 前 Clean。最后用 DWT 或 GPIO 翻转配合逻辑分析仪抓 DMA 请求与 Cache 操作时序,定位错位发生在哪一帧。
mcuku 阿沐 · 2026-10-21