第3章 吞吐率概念:数据传输速率与效率
咱们做嵌入式开发的,天天跟“速率”打交道。SPI 标称能跑 50 Mbps,可实际用起来,连一半都跑不满。问题出在哪?说白了,你看到的“速率”只是物理层的一个上限,真正的数据传输效率,得看吞吐率。
我习惯把吞吐率叫作“能干活的速度”。物理层速率是路标,吞吐率才是你车实际跑上去的速度。中间差了多远?嗯,这章我们就把它掰开揉碎了讲清楚。
3.1 吞吐率不只是数字
先给个定义:吞吐率 是指单位时间内成功传输的有效数据量。单位常用 Mbps 或 MB/s。
注意“有效”二字。你发 100 个字节,里面可能夹着 30 个控制字段、校验码、帧头帧尾。真正对应用有用的,可能只有 70 个字节。这种开销,在计算吞吐率时全得扣掉。
我曾经帮一个同事排查 SPI 显示刷屏慢的问题。他查了 SPI 时钟频率是 20 MHz,算下来理论速率 20 Mbps,可屏幕刷新率死活上不去。后来一测,他每帧数据里塞了 30% 的帧同步头和冗余填充。吞吐率实际只有 14 Mbps 左右。这就是典型“看数字不看结构”的坑。
3.2 两个关键公式
咱们先把数学摆出来。虽然简单,但我建议你每次做性能评估前,都手写一遍这两条式子。
// 公式一:理论峰值吞吐率
Peak = 物理层时钟频率 × 数据线宽度 × (单位时间内时钟沿数)
// 公式二:实际有效吞吐率
Effective = (有效数据量) / (传输总时间)
// 更实用的形式:
Effective =
(总传输数据量 × 有效数据占比)
------------------------------------
预传输耗时 + 传输耗时 + 后处理耗时
第二个公式里的分母,才是决定实际吞吐率的关键。预传输耗时包括:DMA 请求延迟、CPU 对 SPI 外设的配置时间、以及缓冲区分配时间。传输耗时就是实际 SPI 收发的时间。后处理耗时包括中断响应、数据搬移、状态清理。
我在一个项目里遇到过 DMA 请求延迟导致死锁的例子。那个系统里,DMA 每次传输前要等 12 个时钟周期的仲裁和地址映射。12 个周期看起来不多,但每 64 字节就要重复一次。算下来,有效吞吐率直接掉了 18%。
3.3 开销藏在哪里?
你要想提升吞吐率,得先知道开销在哪。我总结了三个大户:
- 协议开销:帧头、帧尾、CRC、控制字节。SPI 本身是字节流,但上层协议(比如 LCD 命令帧、SPI Flash 页编程)常常每发 256 字节就要塞一次命令+地址。这部分开销占比可以在 5% ~ 30% 浮动。
- DMA 请求延迟:从外设产生 DMA 请求到 DMA 控制器实际搬移第一个字节的时间。包括:DMA 仲裁等待(多通道竞争)、源/目标地址准备、以及总线对齐停顿。每次请求的延迟虽然只有几到几十个时钟,但如果传输粒度很小(比如每次 32 字节),延迟占比就会很可观。
- 软件栈开销:驱动层函数调用、中断上下文切换、信号量或互斥锁的加解锁。这些在实时系统里尤其容易忽略。我曾经在一个 FreeRTOS 项目里发现 SPI 发送任务因为等待 DMA 完成信号量,每帧多等了 200 µs。你看,光这 200 µs 就让 2 Mbps 的物理链路实际只能跑 1.2 Mbps。
举个例子,一个典型的 SPI Flash 页写过程:
| 阶段 | 耗时 (µs) | 说明 |
|---|---|---|
| 发送写使能命令 | 3.2 | 8 位命令 + 8 位 dummy |
| 等待 DMA 请求 | 0.8 | DMA 仲裁 + 地址准备 |
| 传输 256 字节数据 | 20.48 | SPI 时钟 100 MHz,单线 |
| 后处理(状态查询) | 5.0 | 轮询忙标志 |
| 总计 | 29.48 | 有效数据占比 = 256 / (总耗时×带宽率) ≈ 87% |
你看,DMA 请求延迟仅 0.8 µs,但加上后处理,有效吞吐率就被拉低了 13%。如果传输粒度更小(比如每次 64 字节),DMA 请求延迟占比会更大。
3.4 效率:你的带宽用了几成?
效率这个指标,说白了就是有效数据占物理传输量的比例。我一般用这个简单公式:
效率 = 有效数据位数 / (物理层传输的总位数) × 100%
还是上面那个 SPI Flash 例子:传 256 字节有效数据,物理层实际发了命令(8位) + 地址(24位) + 空周期(8位) + 256字节数据 + 状态轮询(40位)。总位数约 2208 位。效率 = 2048 / 2208 ≈ 92.8%。
92.8% 看起来不差?但你要知道这是理论最优。实际加上 DMA 请求延迟、CPU 介入、DMA 传输完成中断响应等时间,有效吞吐率往往只有物理层速率的 60%~80%。
我遇到最离谱的一个案例:客户在 SPI 上用了一个极度碎片化的传输策略——每次只发 8 字节就重新配置 DMA。结果物理层 50 MHz,实际有效吞吐率只有 11 Mbps,效率低到 22%。后来改成双缓冲 + 批量传输,直接提到 41 Mbps。
3.5 一张图看懂吞吐率构成
下面这张图把整个数据从应用层到物理线的过程拆开了。你可以看到每一层都会吃掉一部分时间,最终落到“有效吞吐率”那个框里才是你真正在意的东西。
说白了,吞吐率就是所有环节一层层扣除后的净值。我每次做性能评估,都会把这张图画一遍,把每个环节的耗时标上去。哪个环节占比最大,就优先优化哪个。通常在 SPI 项目里,DMA 请求延迟和协议封装是最大的两块。如果二者能同时优化,吞吐率提升 30%~50% 并不难。