3. DMA传输原理入门
在摄像头驱动中,Sensor 会以固定帧率持续输出像素数据,例如 1080p@30fps 时每秒产生约 1.5Gbit 的原始数据。如果这些数据全部由 CPU 逐字节搬运,CPU 将长期陷入“搬砖”状态,无法及时处理帧同步、曝光控制、应用调度等关键任务。DMA(Direct Memory Access,直接存储器访问)正是为解决这一矛盾而设计的硬件机制:它让外设与内存之间建立一条“旁路通道”,由独立的 DMA 控制器完成数据搬运,CPU 只负责配置和收尾。
一、DMA的基本概念与角色
DMA 控制器本质上是一个可编程的数据搬运引擎。它内部维护源地址、目的地址、传输长度、传输宽度、地址递增方式等寄存器。当外设(如摄像头接口 CSI/MIPI)产生数据请求时,DMA 控制器向总线仲裁器申请总线使用权,获得授权后直接在内存与外设 FIFO 之间读写数据,整个过程不需要 CPU 参与逐字节操作。
在摄像头驱动中,DMA 承担三个关键角色:第一,把 CSI 接收到的像素数据写入内核预分配的帧缓冲区;第二,在写入完成后触发中断,通知驱动“一帧已就绪”;第三,通过循环或链式模式维持连续多帧的自动搬运,避免每帧都重新配置。可以说,DMA 是摄像头数据通路的“传送带”,CPU 则是“调度员”。
二、三种典型传输模式
DMA 控制器通常支持多种传输模式,摄像头驱动中最常用的是单次、循环和链式三种。
- 单次传输(Single/Block):配置一次,搬运指定长度后停止并产生中断。适合抓拍单帧、调试阶段或分辨率切换时的临时传输。缺点是每帧都需要 CPU 重新配置,帧率高时中断开销大。
- 循环传输(Circular/Cyclic):DMA 在预设的缓冲区环上自动循环,搬完最后一块后自动回到起始地址继续。适合连续视频流,CPU 只需在缓冲区半满/全满中断中处理数据,显著降低配置频率。
- 链式传输(Scatter-Gather/Linked List):DMA 按描述符链表依次搬运,每个描述符包含源地址、目的地址、长度和下一个描述符指针。适合多平面格式(如 YUV 的 Y/UV 分离存储)、多缓冲区轮转或非连续内存场景。
| 模式 | 触发方式 | CPU 参与度 | 典型摄像头场景 |
|---|---|---|---|
| 单次传输 | 配置一次搬运一次 | 每帧需重新配置 | 单帧抓拍、调试、模式切换 |
| 循环传输 | 缓冲区环自动回绕 | 仅中断处理 | 连续视频流、预览 |
| 链式传输 | 描述符链表驱动 | 初始化链表后极少干预 | 多平面 YUV、多缓冲轮转 |
三、DMA 与 CPU 中断方式的对比
理解 DMA 的价值,最直接的方式是与“CPU 中断搬运”对比。在无 DMA 的系统中,CPU 需要响应每个数据就绪中断,在中断服务程序中读取外设寄存器并写入内存。以 1080p 一帧约 200 万像素、每像素 2 字节计算,若每次搬运 4 字节,一帧需要约 100 万次中断或轮询操作,CPU 几乎无法完成其他工作。
引入 DMA 后,CPU 只在“一帧搬完”或“半帧搬完”时收到一次中断,中断频率从百万级降到几十到几百赫兹。CPU 在中断中只需做三件事:确认 DMA 状态、把缓冲区标记为就绪、唤醒等待队列。数据搬运本身由 DMA 硬件并行完成,CPU 与 DMA 形成流水线协作。
核心结论:DMA 不是“更快的中断”,而是“把搬运工作从 CPU 卸载到专用硬件”。中断方式下 CPU 是搬运工,DMA 方式下 CPU 是调度员。
四、摄像头驱动中的实际配置片段
以 Linux 摄像头驱动为例,DMA 描述符的初始化通常包含源地址、目的地址、长度和回调信息。下面是一段简化的描述符配置示意:
struct dma_desc {
u32 src_addr; // CSI FIFO 地址
u32 dst_addr; // 帧缓冲区物理地址
u32 length; // 一行或一帧的字节数
u32 next; // 下一个描述符地址
u32 ctrl; // 中断使能、循环标志
};
/* 配置循环模式:搬完一帧后自动回到起始地址 */
desc->src_addr = CSI_FIFO_BASE;
desc->dst_addr = frame_buf_phys;
desc->length = frame_size;
desc->ctrl = DMA_CTRL_IRQ_EN | DMA_CTRL_CIRCULAR;
在链式模式下,驱动会预先分配多个描述符,每个描述符指向不同的帧缓冲区,形成“描述符环”。DMA 每完成一个描述符就自动加载下一个,直到环回。这样即使应用层读取速度有波动,DMA 也能持续搬运,不会因为单个缓冲区被占用而阻塞。
五、常见误区与复盘
误区一:认为 DMA 不需要 CPU 参与。DMA 的配置、描述符维护、中断处理和缓冲区管理仍然依赖 CPU。DMA 只是把“逐字节搬运”卸载,而不是把整个数据通路交给硬件。
误区二:忽略缓存一致性。DMA 直接访问内存,可能绕过 CPU Cache。如果驱动没有正确执行 cache flush/invalidate,CPU 读到的可能是旧数据。摄像头驱动中必须在 DMA 完成中断后对缓冲区做 invalidate 操作。
误区三:循环模式缓冲区太小。循环缓冲区过小会导致 DMA 回绕过快,CPU 来不及处理就发生覆盖,表现为画面撕裂或花屏。通常至少需要 3~4 帧的缓冲深度。
调试建议:先用单次模式验证 CSI 配置和帧长度是否正确,再切换到循环模式观察连续帧的稳定性;最后根据格式需求决定是否使用链式模式。每次切换模式后,检查 DMA 中断计数与帧计数是否一致,可快速定位描述符配置错误。
总结来看,DMA 在摄像头驱动中扮演的是“数据搬运加速器”的角色。单次模式适合点状采集,循环模式适合连续流,链式模式适合复杂内存布局。理解三者的差异与适用边界,是后续设计帧缓冲管理和零拷贝通路的基础。