核心原因在于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