Cortex-M Cache、MPU 与 DMA 一致性实战:把 STM32H7 这类高性能 MCU 跑稳跑快

前言:高性能 MCU 最隐蔽的坑,不是算力不够,而是数据“不一致” 很多人第一次从 Cortex-M3 / Cortex-M4 迁移到 Cortex-M7,感受非常直接:主频更高了,FPU 更强了,片上 SRAM 更大了,外设带宽也上来了。以 STM32H7、NXP i.MX RT、部分国产高性能 MCU 为例,系统里开始出现 I-Cache、D-Cache、AXI SRAM、多级总线矩阵、MDMA、ETH、SDMMC、DCMI、LTDC 这类过去在小 MCU 上不太需要认真处理的模块。代码还是 C,外设还是 DMA,调试器还是能单步,但一旦项目进入图像采集、以太网、文件系统、音频流或者屏幕刷新,问题会变得很诡异: DMA 明明已经写完了缓冲区,CPU 读到的还是旧数据; CPU 明明把发送包填好了,以太网 DMA 发出去的却是上一帧; 关掉 D-Cache 后系统稳定了,但吞吐掉了一大截; 加了一句 SCB_CleanDCache_by_Addr() 后偶尔好、偶尔坏; 同样的代码 Debug 版本正常,Release 版本或者换了优化等级就出错; 缓冲区长度不是 32 字节倍数时,旁边的变量被“莫名其妙”污染。 这些现象的根源通常不是外设驱动写错,也不是编译器“玄学”,而是 CPU、Cache、MPU、DMA 对同一段内存的理解不一致。Cortex-M7 的 D-Cache 提升了 CPU 访问速度,但 DMA 控制器通常不会经过 D-Cache,它直接从 SRAM 或外部 RAM 读写。于是同一个地址,在 CPU 看来可能是 Cache Line 里的新数据,在 DMA 看来却是内存里的旧数据;反过来,DMA 已经把新数据写入内存,CPU 仍然命中旧的 Cache Line。...

June 8, 2026 · 8 min · 👁️ 0 · Tech Snippets

DDR 内存带宽调优实战:从 AXI 总线到 Cache Miss 的 SoC 性能优化指南

前言 做嵌入式 Linux 或边缘 AI 项目时,很多性能问题最后都会绕回一个朴素但容易被低估的事实:算力不等于吞吐,CPU、NPU、GPU 跑得再快,只要数据喂不上去,整机性能就会被内存系统卡住。 我第一次真正意识到 DDR 带宽的重要性,是在一块多核 ARM SoC 上做 4 路摄像头视频分析。算法同事看 NPU 利用率只有 40% 左右,以为模型还可以继续加大;系统同事看 CPU 使用率也不高,以为瓶颈不在软件。直到我们把 ISP、RGA、NPU、VPU 同时压起来,再去读 DDR 控制器计数器,才发现内存读写已经接近平台可持续带宽的上限。那一刻,所谓“还有很多算力没用上”,其实只是“大家都在等内存”。 这篇文章想把这个问题讲透一点:DDR 带宽不是一个孤立参数,它贯穿了 CPU Cache、AXI/NoC 互联、DMA burst、内存控制器调度、DRAM Bank 冲突、刷新开销以及 Linux 调度策略。很多项目里大家会直接跑一个 memcpy 或 stream,看到数字不错就认为内存没问题;但真实业务往往不是连续大块搬运,而是多个主设备同时访问、读写混合、缓存命中率波动、实时任务和后台任务互相抢总线。 本文会从 SoC 视角出发,拆解一条内存访问路径,并给出一套可以落地的排查和优化方法。示例代码以 Linux 用户态为主,兼顾裸机/RTOS 下的思路。目标不是把每个 DDR 时序参数都背下来,而是建立一个工程上有用的判断框架:什么时候该看 Cache Miss,什么时候该看 AXI outstanding,什么时候该怀疑 DDR controller 的 page policy,什么时候该从数据布局和 DMA burst 入手。 一、先把“带宽”这件事说清楚 DDR 厂商手册里常见的理论带宽计算很简单: 理论带宽 = 数据总线宽度 / 8 × 数据传输速率 例如 32-bit LPDDR4X,数据速率 4266 MT/s,理论峰值约为:...

June 1, 2026 · 6 min · 👁️ 0 · Tech Snippets