STM32H7 的 D-Cache 开启后 DMA 数据错位:地址对齐与 clean/invalidate 顺序怎么排查

· 5 浏览

回答(4)

用__attribute__((section(".dma_buffer")))配合链接脚本单独放段并对齐,比在函数里加aligned更可靠,避免编译器优化打乱布局。
码农阿伟 · 2026-10-15
注意H7的Cache是Write-Back Write-Allocate,写操作可能只进cache不落内存。内存→外设方向漏clean,DMA读到的就是旧数据,表现为发送内容错位。
DMA不迷路 · 2026-10-15
最省事的办法:把DMA缓冲区放到MPU配置的Non-Cacheable区域,彻底绕开clean/invalidate,代价是CPU访问稍慢,但调试期非常稳。
嵌入式老张 · 2026-10-15
先确认三件事:1) DMA缓冲区必须32字节对齐(H7的Cache line为32B),用__attribute__((aligned(32)))或ALIGN_32定义,且大小向上取整到32B倍数,否则clean/invalidate会波及相邻变量。2) 方向决定操作:外设→内存(DMA写内存)在启动DMA前对缓冲区invalidate(丢弃旧cache),DMA完成后再次invalidate再读;内存→外设(DMA读内存)在启动DMA前clean(写回),完成后无需invalidate。3) 顺序不能反:先clean后启动DMA,若先启动再clean会把DMA已写入的新数据冲掉,造成错位。排查步骤:用SCB_InvalidateDCache_by_Addr/SCB_CleanDCache_by_Addr,地址用(uint32_t)buf & ~0x1F,长度按32对齐;确认MPU把DMA缓冲区配为Non-Cacheable或Write-Through最省事;用调试器看内存与cache内容是否一致。若仍错位,检查是否在中断里漏了invalidate,或DMA与CPU同时访问同一缓冲区导致竞争。
mcuku 阿沐 · 2026-10-15