4. DMA 传输带宽计算:单次传输大小、传输周期、带宽公式与实测差异

带宽这东西,说白了就是「单位时间能搬多少数据」。

DMA 的带宽不是你拍脑袋定的,它和 SPI 时钟频率、传输模式、系统总线负载都绑在一起。我在项目里见过有人 SPI 时钟配了 80 MHz,DMA 却只能跑 30 MB/s,一查才发现是传输周期算错了。嗯,今天咱们就把这笔账算清楚。

4.1 单次传输大小

DMA 每次触发,搬多少数据?这由两个参数决定:

  • 数据宽度:8 位、16 位、32 位(常见于 STM32 等 MCU)
  • 突发传输长度:1、4、8、16 次(取决于 DMA 控制器)

你想想看,单次传输大小 = 数据宽度 × 突发长度。比如用 32 位宽度 + 突发 4 次,就是 16 字节一次。但这里有个坑:很多 SPI 外设只支持 8 位或 16 位 FIFO,你配了 32 位宽度,实际可能被截断或对齐出错。我遇到过用 32 位 DMA 写 SPI 寄存器,结果高位数据丢了,排查了半天才意识到是硬件限制。

个人习惯: SPI 配合 DMA 时,我一般直接用 8 位宽度 + 突发 4 次或 8 次。这样既简单,又避免对齐问题。

4.2 传输周期

一次 DMA 传输需要多少个时钟周期?它包括三个阶段:

  1. 仲裁等待:总线被其他主控占用,DMA 等着。
  2. 源地址读取:从存储器或外设取数据。
  3. 目标地址写入:写到 SPI 发送寄存器(或内存)。

大多数 MCU 的 DMA 是单周期传输的,即 1 个总线时钟完成一次搬移。但如果是非对齐地址,或跨了 AHB 桥,可能插入等待周期。我在一次调试中,DMA 把数据从 SRAM 搬到 SPI,结果 SPI 时钟 40 MHz,DMA 却只能跑到 20 MB/s,原因就是 SRAM 和 SPI 不在同一个总线矩阵上,多了两个等待周期。所以,传输周期 ≈ 1 个总线时钟 × (1 + 等待因子)。

4.3 带宽公式

理论带宽 = (单次传输大小) / (传输周期) 。用总线时钟频率换算一下:

// 假设:
// 总线时钟 = 80 MHz
// 单次传输大小 = 1 字节(8 位)
// 传输周期 = 1 个总线时钟(无等待)

理论带宽 = 80 MHz × 1 字节 = 80 MB/s

// 但 SPI 是有时钟的,实际受限于 SPI 时钟。
// 如果 SPI 时钟 = 40 MHz,全双工一次可收+发 1 字节,
// 则 DMA 理论传输带宽 = 40 MHz × 1 字节 = 40 MB/s

明白了?带宽要取总线侧和 SPI 侧的较小值。我见过有人用 80 MHz 总线时钟去算 DMA 带宽,觉得能跑 80 MB/s,结果 SPI 时钟只有 10 MHz,DMA 再快也只能干等着。说白了,瓶颈在慢的那一端。

参数 典型值 影响带宽
总线时钟 80 MHz 决定了 DMA 最大吞吐
SPI 时钟 40 MHz 直接限制传输速率
数据宽度 8 / 16 / 32 位 每次传输的字节数
等待周期 0~3 个时钟 增加传输时间,降低有效带宽

4.4 实测差异

理论公式算出来漂亮,实际一测,常常打八折。为什么会这样?

  • DMA 请求间隔:SPI 发送完一个字节后,才会触发下次 DMA 请求。如果 SPI 自身 FIFO 深度小(比如 1 个字节),DMA 就被 SPI 的节奏拖着走,带宽自然上不去。
  • 总线仲裁冲突:CPU 或其他外设也在抢总线,DMA 会等。实测时把其他中断关掉,带宽能提升 10~20%。
  • DMA 初始化开销:有些 DMA 需要重新配置源/目标地址,这部分时间没算进传输周期。
  • 缓存一致性问题:如果你用了带 Cache 的 MCU,DMA 读到的是旧数据,必须手动 clean/invalidate,这部分软件开销也会吃掉带宽。
我曾经踩过的坑: 在 STM32H7 上,DMA 从 DTCM RAM 搬到 SPI,理论带宽 200 MB/s,实测只有 60 MB/s。原因之一是 DTCM 只能被 CPU 直接访问,DMA 得绕 AXI 总线,多了延迟。后来换成 SRAM1,带宽直接翻倍。所以,一定要查数据手册的 DMA 可访问地址映射。

做个实验:用逻辑分析仪抓 SPI 的 SCK 和 DMA 的请求信号,看看实际 SCK 的脉冲间隔。如果间隔比理论值大,说明 DMA 在等总线。我习惯在代码里加一个 GPIO 翻转来标记 DMA 完成,用示波器量——这比算半天都准。

核心结论:
实际带宽 ≈ min(总线带宽, SPI 带宽) × (1 - 总线冲突率) × (1 - 等待开销)
如果你能保证 SPI FIFO 深度 ≥ 2,且 DMA 与 CPU 分时使用总线,实测一般能到理论值的 80%~90%。
DMA 传输带宽计算流程 单次传输大小 宽度 × 突发长度 传输周期 等待因子 + 总线时钟 总线 / SPI 时钟 取最小值 理论带宽 = 单次大小 / 周期 单位时间搬数据量(MB/s) 实测差异因素 DMA请求间隔 · 总线仲裁 · Cache · 地址映射 实际带宽 = 理论 × (1 - 开销) × 效率因子 选瓶颈参数