2. DMA硬件架构:DMA控制器内部组成与传输类型
DMA(Direct Memory Access)控制器是系统中负责在无需CPU干预的情况下,直接在外设与内存之间、或内存与内存之间搬运数据的硬件模块。理解DMA控制器的内部组成和传输类型,是驱动开发的基础。本章将深入剖析DMA控制器的核心组件与工作模式。
2.1 DMA控制器内部组成
一个典型的DMA控制器内部由多个功能单元协同工作,主要包括通道(Channel)、请求线(Request Line)和仲裁器(Arbiter)。下图展示了DMA控制器的内部架构。
2.1.1 DMA通道(Channel)
每个DMA通道本质上是一组硬件寄存器,用于描述一次DMA传输的全部参数。通道是DMA传输的执行单元,每个通道可以独立配置并处理一个数据传输任务。
| 寄存器名称 | 功能描述 | 位宽(典型) |
|---|---|---|
| 源地址寄存器 | 存储数据源的起始地址(内存地址或外设地址) | 32位 / 64位 |
| 目的地址寄存器 | 存储数据目的地的起始地址 | 32位 / 64位 |
| 传输计数寄存器 | 记录待传输的数据量(字节数或传输次数) | 16位 / 32位 |
| 控制寄存器 | 配置传输方向、数据宽度、突发长度、中断使能等 | 16位 / 32位 |
| 状态寄存器 | 指示传输完成、错误、通道忙等状态 | 8位 / 16位 |
驱动开发提示: 在Linux DMA引擎驱动中,每个通道对应一个
dma_chan 结构体。驱动通过 dma_request_channel() 申请一个空闲通道,并在传输完成后通过 dma_release_channel() 释放。
2.1.2 请求线(Request Line)
请求线是外设向DMA控制器发起数据传输请求的硬件信号线。每个支持DMA的外设(如UART、SPI、I2S、ADC)都有一条或多条专用的DMA请求线,连接到DMA控制器的请求输入引脚。
- 硬件触发: 当外设准备好发送或接收数据时,会通过请求线向DMA控制器发送脉冲信号。
- 通道映射: 请求线通过硬件路由或寄存器配置,映射到特定的DMA通道。例如,UART1的TX请求线映射到通道0,RX请求线映射到通道1。
- 电平/边沿触发: 请求信号可以是电平触发(持续有效)或边沿触发(单次脉冲),具体取决于硬件设计。
2.1.3 仲裁器(Arbiter)
当多个DMA通道同时有传输请求时,仲裁器负责决定哪个通道获得总线使用权。仲裁策略直接影响系统的实时性和吞吐量。
| 仲裁策略 | 工作原理 | 适用场景 |
|---|---|---|
| 固定优先级 | 通道编号越小优先级越高(如通道0 > 通道1) | 对延迟敏感的实时外设(如音频) |
| 轮询(Round-Robin) | 所有通道轮流获得总线使用权,公平分配带宽 | 多个外设带宽需求相近的场景 |
| 混合策略 | 高优先级通道使用固定优先级,其余使用轮询 | 既有实时要求又有批量传输的复杂系统 |
常见陷阱: 在驱动初始化时,务必检查仲裁器配置寄存器。某些SoC默认将所有通道设为相同优先级,导致高带宽外设(如显示控制器)与低带宽外设(如UART)竞争时出现数据丢失。
2.2 DMA传输类型
根据数据源和目的地的不同,DMA传输分为三种基本类型。下图展示了这三种传输类型的数据流向。
2.2.1 内存到内存(Memory-to-Memory)
数据源和目的地都是内存区域。这种模式通常用于快速内存拷贝、帧缓冲复制或数据搬移。CPU只需配置一次DMA通道,即可完成大块数据的搬运,无需逐字节参与。
- 典型应用: 图像处理中的帧复制、网络协议栈中的skb拷贝、用户态与内核态数据交换。
- 特点: 不需要外设请求线触发,由软件启动传输;传输完成后产生中断通知CPU。
- 驱动配置: 设置源地址为内存A的地址,目的地址为内存B的地址,传输计数为数据长度,方向为内存到内存。
2.2.2 外设到内存(Peripheral-to-Memory)
数据从外设(如UART接收FIFO、SPI接收寄存器、ADC数据寄存器)传输到内存缓冲区。这是嵌入式系统中最常见的DMA使用场景。
- 典型应用: 串口接收不定长数据、音频ADC采集、摄像头数据捕获。
- 特点: 由外设的DMA请求线触发传输;外设每准备好一个数据单元,就发送一次请求。
- 驱动配置: 源地址固定为外设数据寄存器地址(通常不递增),目的地址为内存缓冲区地址(递增),传输方向为外设到内存。
2.2.3 内存到外设(Memory-to-Peripheral)
数据从内存缓冲区传输到外设(如UART发送FIFO、SPI发送寄存器、DAC输入寄存器)。
- 典型应用: 串口发送数据、音频DAC输出、SPI控制LCD显示。
- 特点: 同样由外设请求线触发;外设发送寄存器空时发起请求,DMA从内存读取数据写入外设。
- 驱动配置: 源地址为内存缓冲区地址(递增),目的地址固定为外设数据寄存器地址(不递增),传输方向为内存到外设。
关键对比: 三种传输类型在驱动配置上的核心差异在于地址递增模式和触发方式。内存到内存传输中,源和目的地址通常都递增;外设相关的传输中,外设一侧的地址固定不变。下表总结了这些差异。
| 传输类型 | 源地址模式 | 目的地址模式 | 触发方式 | 典型数据宽度 |
|---|---|---|---|---|
| 内存→内存 | 递增 | 递增 | 软件触发 | 32位 / 64位 |
| 外设→内存 | 固定(外设寄存器) | 递增 | 外设请求线触发 | 8位 / 16位 / 32位 |
| 内存→外设 | 递增 | 固定(外设寄存器) | 外设请求线触发 | 8位 / 16位 / 32位 |
2.3 传输粒度与突发传输
DMA传输的数据宽度(Data Width)和突发传输(Burst Transfer)是影响传输效率的重要参数。
- 数据宽度: 每次DMA请求传输的数据位数,常见为8位(字节)、16位(半字)、32位(字)。必须与外设的数据寄存器宽度匹配。
- 突发传输: 在一次总线仲裁后连续传输多个数据单元,减少总线仲裁开销。突发长度通常为4、8、16个数据单元。
性能优化: 对于高速外设(如SDIO、以太网),建议使用较大的突发长度(如16个32位字)以提高总线利用率。对于低速外设(如UART),使用单次传输或小突发长度,避免长时间占用总线影响其他外设。