Lazy loaded image
Words 0Read Time 1 min
Invalid Date
🎯
核心判断
DMA 在真实驱动里解决的,从来不只是“少拷几次”。它真正解决的是:让数据搬运脱离 CPU 主执行路径,把吞吐、时延和 CPU 占用从同一个瓶颈里拆出来。

这一章解决什么问题

很多人学 DMA,一上来就背定义:Direct Memory Access,设备可直接访问内存。定义当然没错,但工程价值接近零。
 
你真正该问的是:
  • 为什么有些驱动用 PIO 还能活,一上吞吐就开始抽风?
  • 为什么一旦进入音频、网络、视频、采集这类持续流场景,DMA 很快从“可选优化”变成“通路基础设施”?
  • 为什么同样是“能跑”,有的实现 CPU 忙得像狗,有的实现却能把 CPU 留给真正的控制逻辑?

先把错误认知打掉

误区 1:DMA 只是性能优化

错。对很多驱动来说,DMA 不是锦上添花,而是决定架构形态的分水岭。
 
没有 DMA,你的数据路径通常是:
  1. 设备发出事件
  1. CPU 进入中断或轮询
  1. CPU 一次次从寄存器/FIFO 搬数据
  1. 数据量一大,CPU 时间被搬运吞掉
 
有 DMA 后,路径变成:
  1. 驱动配置 buffer 和描述符
  1. 设备直接把数据写进内存,或从内存取数据
  1. CPU 主要处理提交、完成、回收和控制逻辑
 
区别不在“是否更快”,而在“CPU 是否还亲自扛着数据搬运这口锅”。

误区 2:只要吞吐高就一定上 DMA

也错。DMA 不是白送的。
 
你引入 DMA 的同时,也引入了:
  • buffer 生命周期管理
  • cache 一致性问题
  • ownership 切换
  • completion / timeout / reset 清理
  • 用户态协议设计(如果走零拷贝)
 
所以 DMA 的判断标准不是“能不能用”,而是:
引入 DMA 后,整体系统收益是否大于复杂度账单。

CPU 搬运 vs DMA 搬运:本质差别

维度
CPU 直接搬运
DMA 搬运
数据搬运主力
CPU
设备 / DMA 控制器
CPU 角色
既控制又搬运
主要负责配置、同步、完成处理
适合场景
低吞吐、偶发、控制面操作
大块、持续流、低 CPU 占用要求
主要瓶颈
CPU 时间、总线访问频率
buffer 设计、一致性、调度与回收
复杂度来源
实现简单,但吞吐差
实现复杂,但扩展性强

三类最典型场景

1. 一次性大块搬运

比如:固件下载、图像帧一次性传输、大块存储读写。
 
这类场景的重点是:
  • 数据量大
  • 一次事务较长
  • 对单次搬运效率敏感
 
DMA 在这里主要解决:别让 CPU 用 memcpy 的姿势给自己上刑。

2. 持续流式收发

比如:音频采集、摄像头视频流、网络包收发、ADC 连续采样。
 
这类场景里,DMA 往往不是“更快一点”,而是“没有它很难长期稳定运行”。
 
因为系统要持续面对:
  • 周期性数据到达
  • ring buffer 推进
  • completion 回收
  • 上层消费速度不稳定
 
这也是本专题选择采集型 / 流式设备驱动作为主线案例的原因:它能把 DMA 真正难的部分全暴露出来。

3. 零拷贝用户态协作

比如:用户态直接消费设备采集到的大块数据。
 
这时 DMA 不只是解决“搬运”,还会反过来要求你设计:
  • buffer ownership
  • mmap 数据面
  • ioctl/poll 控制面
  • submit / wait / consume 协议
 
从这里开始,DMA 已经不是函数调用问题,而是系统协作协议问题

哪些设备天然更需要 DMA

设备类型
是否应优先考虑 DMA
原因
UART(低速控制)
视吞吐而定
低速下 PIO 足够;高波特率持续流时 DMA 更稳
音频接口 I2S / SAI
通常是
持续流、周期稳定、CPU 不应亲自搬样本
摄像头 / 视频采集
基本是
数据量大、帧流持续、缓冲管理复杂
网络设备
基本是
吞吐与延迟要求高,描述符 + ring 是常态
ADC / 采集卡
通常是
连续采样天然适合 DMA 周期搬运
I2C 配置型外设
通常不是重点
控制面为主,搬运量通常不大

什么时候不该急着上 DMA

1. 数据量小,而且是低频控制操作

如果只是偶发寄存器读写、小块配置、低速命令通道,DMA 很可能是在给自己加戏。

2. 硬件路径本身不支持,或支持得很残

有些设备“理论支持 DMA”,实际 descriptor、对齐、地址范围、completion 行为都很别扭。这个时候硬上 DMA,得到的通常不是优雅,而是漫长的调试岁月。

3. 你的系统瓶颈根本不在搬运

如果真正卡的是:
  • 用户态处理太慢
  • 上层协议太重
  • 锁竞争严重
  • 中断风暴
 
那你把 PIO 换成 DMA,也只是换一种姿势堵车。

一个工程上真正有用的判断框架

问题 1:数据搬运是否正在占用 CPU 的主路径预算?

如果 CPU 大量时间浪费在搬数据,而不是做控制、调度、协议、算法,那 DMA 值得考虑。

问题 2:数据是否是持续流,而不是偶发点状事件?

越接近持续流,DMA 的收益越大。

问题 3:是否需要把用户态、驱动、设备组成一条高吞吐数据管线?

如果是,那 DMA 往往会直接决定后续 buffer 和协议设计。

问题 4:你是否愿意承担 DMA 带来的治理成本?

包括:
  • 生命周期
  • ownership
  • sync
  • reset / timeout 清理
  • debug 与验证
 
如果不愿意,那就别碰。别一边想要高速,一边又只想要玩具级复杂度。工程世界没这种便宜。

一个主线案例的直觉图

这个图里最重要的不是箭头,而是一个残酷事实:
 
你一旦采用 DMA,就必须开始治理“谁在什么时候拥有 buffer”。
 
所以本专题后面会把重点放在:
  • ownership
  • lifecycle
  • ring buffer
  • mmap 协议
  • error path
 
因为这些才是“真实驱动开发”真正会把人绊倒的地方。

本章结论

  1. DMA 的本质价值,是把数据搬运从 CPU 主路径中剥离出来。
  1. 它在一次性大块传输里是加速器,在持续流设备里更像基础设施。
  1. DMA 不是单纯 API 技巧,而是会反向决定 buffer、协议和调试模型的系统设计。
  1. 只要进入流式、高吞吐、低 CPU 占用场景,你迟早要面对 DMA,而且最好别用侥幸心理面对。

下一章要干什么

下一章不讲 API,先把一次 DMA 传输的全链路图摊开。
 
因为在真正写驱动前,你得先知道:
  • 数据究竟怎么流
  • 控制究竟怎么走
  • 设备、内存、cache、用户态各自站在哪一层
 
否则你后面学的每个函数,都只是在记碎片。
上一篇
Data Structure and Algorithm
下一篇
用面试拷问嵌入式技术栈

Comments
Loading...