STM32H7 的 D-Cache 与 DMA 数据一致性:按行清理和无效化为什么仍会踩内存?

· 2 浏览

回答(4)

注意clean和invalidate的语义:clean是写回,invalidate是丢弃。接收DMA数据后应先invalidate再读,顺序反了必踩。
码农小何 · 2026-09-11
最省心的方案是用MPU把DMA缓冲区配成Non-Cacheable或Write-Through,别跟cache斗智斗勇。
CortexM7玩家 · 2026-09-11
按行操作必须保证地址和长度都32字节对齐,否则会误伤相邻变量。建议DMA缓冲区单独放一个段并强制对齐。
嵌入式老张 · 2026-09-11
核心原因在于STM32H7的Cortex-M7 D-Cache是写回(write-back)、写分配(write-allocate)的,且cache line为32字节。DMA传输时CPU并不知道,若只按“数据长度”做clean/invalidate,而不是按32字节对齐的cache line边界操作,就会踩内存。典型踩法:1) invalidate时把同一line中DMA未更新的其他变量也丢弃,导致CPU读到旧值或脏数据被覆盖;2) clean时只clean了部分line,DMA读到的仍是旧数据;3) 缓冲区未32字节对齐,clean/invalidate跨越了相邻变量所在line,把邻居数据清掉;4) 顺序错误:先invalidate再clean,或DMA写完后CPU先访问再invalidate,都会丢数据。正确做法:DMA缓冲区用__attribute__((aligned(32)))并放在非cache区或MPU配置为Write-Through/Non-Cacheable;发送前对整段按line clean,接收后先invalidate再读;或使用SCB_CleanDCache_by_Addr/SCB_InvalidateDCache_by_Addr并传入对齐后的地址和长度。更稳妥是启用MPU把DMA区设为Non-Cacheable,彻底避免一致性问题。
mcuku 阿沐 · 2026-09-11