V4L2视频缓冲队列开发与DMA内存管理 - 第1节

1.1 DMA 工作原理

直接存储器访问(Direct Memory Access, DMA)是一种允许硬件设备直接与系统内存进行数据交换,而无需 CPU 逐字节干预的机制。在多媒体驱动开发中,DMA 是摄像头、显示控制器、音频接口等高速外设与内存之间传输帧数据、音频样本的核心通道。

核心价值:DMA 将 CPU 从繁重的数据搬运任务中解放出来,使 CPU 可以专注于协议解析、控制逻辑和上层应用处理,从而大幅提升系统吞吐量并降低延迟。

1.1.1 无 DMA 与有 DMA 的对比

对比维度 无 DMA(PIO 模式) 有 DMA 模式
数据搬运主体 CPU 逐字读取/写入 DMA 控制器硬件自动搬运
CPU 占用率 高(100% 占用直到传输完成) 低(仅初始化时参与,传输中可执行其他任务)
传输速率 受限于 CPU 指令周期 接近总线带宽,可达数 GB/s
适用场景 小数据量、低速设备(如 UART) 大数据块、高速设备(如 Camera、GPU、NVMe)

1.1.2 DMA 基本工作流程

  1. 设备请求:外设(如摄像头控制器)准备好数据后,向 DMA 控制器发送 DMA 请求信号(DREQ)。
  2. 总线仲裁:DMA 控制器向 CPU 请求总线控制权(HRQ),CPU 在完成当前总线周期后让出总线(HLDA)。
  3. 地址与计数加载:DMA 控制器从寄存器中读取源地址、目标地址和传输字节数。
  4. 数据传输:DMA 控制器在总线周期内直接在外设与内存之间搬运数据,每传输一个单元自动递增地址并递减计数。
  5. 传输完成:当计数归零时,DMA 控制器向 CPU 发送中断信号(DMA_IRQ),通知传输结束。
DMA 基本工作流程 外设请求 DREQ 总线仲裁 HRQ/HLDA 加载地址/计数 DMA 数据传输 计数归零 → 中断 说明: DMA 传输期间 CPU 可以执行其他任务,仅在传输开始和结束时参与。 传输完成后通过中断通知 CPU,CPU 处理数据或启动下一轮传输。

1.2 DMA 控制器

DMA 控制器(DMAC)是负责执行 DMA 传输的硬件模块。在嵌入式 SoC 中,DMAC 通常作为系统总线上的一个主设备存在,拥有独立的总线控制能力。

1.2.1 DMA 控制器内部结构

  • 控制寄存器组:配置传输方向、传输模式、地址递增方式等参数。
  • 源地址寄存器(SAR):存放数据源地址(外设 FIFO 或内存地址)。
  • 目标地址寄存器(DAR):存放数据目标地址(内存或外设 FIFO)。
  • 传输计数寄存器(TCR):记录剩余待传输的数据单元数。
  • 通道仲裁逻辑:管理多个 DMA 通道的优先级和并发请求。
DMA 控制器内部结构 DMA 控制器 (DMAC) 控制寄存器组 通道仲裁逻辑 SAR / DAR TCR 系统总线接口 外设接口 SAR/DAR 决定数据流向;TCR 决定传输长度;通道仲裁决定多请求时的服务顺序。

1.3 DMA 传输模式

根据传输过程中总线控制权的释放策略,DMA 主要分为以下三种模式:

传输模式 工作方式 总线占用 典型场景
单次传输(Single Transfer) 每传输一个单元(字节/字)后释放总线,重新仲裁 低,每次传输后释放 低速外设、多设备共享总线
块传输(Block Transfer) 一次请求完成整个数据块的传输,期间不释放总线 高,传输期间独占总线 高速数据流(Camera、Audio)
请求传输(Demand Transfer) 外设通过 DREQ 信号控制传输节奏,信号有效时持续传输 动态,由外设速率决定 FIFO 半满触发传输的外设
驱动开发提示:在 videobuf2 框架中,DMA 传输通常采用块传输模式,以确保帧数据在指定时间内完整到达内存缓冲区。对于需要流控的场景(如音频),请求传输模式更为常见。

1.4 DMA 与 CPU 交互

DMA 与 CPU 之间的高效协作是多媒体驱动稳定运行的关键。两者通过以下机制实现同步与数据共享:

1.4.1 交互机制

  • 中断通知:DMA 传输完成后触发中断,CPU 在中断服务例程(ISR)中处理数据或启动下一轮传输。
  • 轮询状态寄存器:CPU 通过读取 DMA 控制器的状态寄存器判断传输是否完成,适用于低延迟或中断不可用的场景。
  • 描述符链(Descriptor Chain):DMA 控制器自动从内存中读取下一个传输描述符,实现多缓冲区连续传输而无需 CPU 逐次干预。
  • Cache 一致性维护:DMA 直接访问物理内存,CPU 使用 Cache 时需通过 dma_map_single / dma_sync_single_for_cpu 等 API 保证数据一致性。
DMA 与 CPU 交互模型 CPU 中断处理 / 配置 DMA 控制器 数据传输引擎 系统内存 Buffer / 描述符 配置/启动 DMA 读写 中断信号 (IRQ) 关键交互点: ① CPU 配置 DMA 源/目标地址和传输长度 → ② DMA 独立传输数据 → ③ 传输完成触发中断 ④ CPU 在中断中处理数据或提交新描述符 → 循环

1.4.2 Cache 一致性处理

常见陷阱:DMA 直接访问物理内存,而 CPU 可能将数据缓存在 Cache 中。如果 CPU 修改了缓冲区但未刷回内存,DMA 读取到的将是陈旧数据;反之,DMA 写入内存后 CPU 从 Cache 读取也可能拿到旧值。必须使用 DMA API 保证一致性。
API 函数 用途 调用时机
dma_map_single() 映射缓冲区并执行必要的 Cache 刷回/失效 DMA 传输开始前
dma_unmap_single() 解除映射并同步 Cache DMA 传输完成后
dma_sync_single_for_cpu() 将缓冲区所有权交还给 CPU(Cache 失效) CPU 读取 DMA 写入的数据前
dma_sync_single_for_device() 将缓冲区所有权交给设备(Cache 刷回) CPU 写入数据供 DMA 读取前
实战要点:在 videobuf2 框架中,vb2_dma_contig 和 vb2_dma_sg 内存分配器内部已经封装了上述 DMA API 的调用。驱动开发者只需正确实现 buf_prepare 和 buf_finish 回调,框架会自动处理 Cache 一致性。