2. DMA控制器硬件架构
DMA(Direct Memory Access)控制器是嵌入式系统中负责在内存与外设之间、或内存与内存之间直接传输数据的关键硬件模块。理解其内部组成与常见类型,是编写高效、稳定DMA驱动的前提。本章将深入剖析DMA控制器的核心组件,并对比两种广泛使用的商用DMA控制器:ARM PL330与Synopsys DW_axi_dmac。
2.1 DMA控制器内部组成
一个典型的DMA控制器由多个功能单元协同工作,主要包括:通道(Channel)、仲裁器(Arbiter)、地址发生器(Address Generator)以及控制逻辑与状态寄存器。下图展示了其内部架构关系。
2.1.1 通道(Channel)
通道是DMA控制器的基本执行单元。每个通道独立管理一次数据传输任务,包含以下关键寄存器与逻辑:
- 源地址寄存器(SAR):存储数据读取的起始地址。
- 目的地址寄存器(DAR):存储数据写入的起始地址。
- 传输计数寄存器(CTL/BCR):记录待传输的数据量(字节数或块数)。
- 控制配置寄存器(CCR):配置传输方向、数据宽度、突发大小、中断使能等。
- 状态寄存器:指示通道是否忙碌、传输完成、错误等状态。
驱动开发要点: 在多通道场景下,驱动需要为每个通道维护独立的描述符链表和回调函数上下文。通道的分配与释放是驱动设计中的关键资源管理环节。
2.1.2 仲裁器(Arbiter)
当多个通道同时请求系统总线进行数据传输时,仲裁器负责决定总线使用权。常见的仲裁策略包括:
| 仲裁策略 | 描述 | 适用场景 |
|---|---|---|
| 固定优先级 | 通道编号越小(如通道0),优先级越高。高优先级通道可抢占低优先级通道。 | 实时性要求高的关键数据流(如音频、视频)。 |
| 轮询(Round-Robin) | 所有通道按顺序轮流获得总线使用权,保证公平性。 | 多个外设带宽需求相近的场景(如多路UART、SPI)。 |
| 混合策略 | 将通道分组,组内固定优先级,组间轮询。 | 兼顾关键流与公平性的复杂系统。 |
2.1.3 地址发生器(Address Generator)
地址发生器在每次数据传输后,根据配置自动更新源地址和目的地址。其支持的模式直接影响驱动对描述符的构建方式:
- 线性模式(Linear):地址连续递增或递减,适用于内存块拷贝或线性缓冲区。
- 循环模式(Circular):地址到达边界后回绕到起始地址,适用于音频环形缓冲区。
- 1D/2D 分块模式:支持行内连续、行间跨步的地址跳转,适用于图像帧缓冲区或矩阵转置。
2.2 常见DMA控制器类型
不同厂商的DMA控制器在架构、编程模型和功能特性上存在差异。以下重点介绍两种在嵌入式Linux中广泛使用的DMA控制器:ARM PL330 和 Synopsys DW_axi_dmac。
2.2.1 ARM PL330 DMA控制器
PL330是ARM公司推出的高性能DMA控制器,常见于基于AMBA总线的SoC(如Exynos、STM32MP系列)。其核心特点如下:
- 微程序引擎:PL330内部包含一个微控制器,通过执行DMA微指令(DMA指令集)来完成复杂传输序列,而非简单的寄存器配置。
- 描述符链(Descriptor Chain):支持链表式描述符,每个描述符指向下一个描述符,实现无需CPU干预的连续传输。
- 事件与中断管理:每个通道可配置多个事件触发点(传输完成、半传输、错误),中断控制器可灵活屏蔽与路由。
- 通道数量:通常支持8个通道,每个通道可独立配置。
2.2.2 Synopsys DW_axi_dmac DMA控制器
DW_axi_dmac是Synopsys DesignWare系列中的AXI总线DMA控制器,广泛应用于高性能SoC(如Zynq、Intel SoC FPGA)。其核心特点如下:
- AXI总线接口:原生支持AXI4/AXI4-Stream协议,具备高带宽和低延迟特性。
- 多块传输(Multi-Block):支持硬件链表(Hardware Linked List),描述符存储在内存中,由硬件自动遍历。
- 可编程突发大小:支持1到256字节的突发传输,可针对不同外设优化总线效率。
- 中断聚合:支持多个中断源合并为一个中断信号,减少CPU中断处理次数。
| 特性 | ARM PL330 | Synopsys DW_axi_dmac |
|---|---|---|
| 总线协议 | AMBA AHB/AXI | AXI4 / AXI4-Stream |
| 描述符管理 | 微指令 + 链表 | 硬件链表(内存描述符) |
| 通道数量 | 最多8通道 | 最多16通道 |
| 传输粒度 | 字节/半字/字 | 字节/半字/字/双字 |
| 中断处理 | 每通道独立中断 | 支持中断聚合 |
| 典型应用 | 移动SoC、MCU | FPGA、高端嵌入式 |
2.2.3 驱动开发视角的对比
从驱动开发角度看,两种控制器在描述符接口设计上存在显著差异:
- PL330:驱动需要构建微指令序列(DMA指令),通过
dmaengine_prep_slave_sg()等API提交。描述符的完成回调在微指令执行完毕后触发。 - DW_axi_dmac:驱动直接填充内存中的描述符结构体(如
dw_axi_dma_lli),设置llp(链表指针)字段链接下一个描述符。硬件自动遍历链表,无需微指令。
常见陷阱: 在DW_axi_dmac中,描述符链表必须位于非缓存(non-cacheable)内存区域,否则硬件可能读取到过时的描述符数据。驱动开发时需使用
dma_alloc_coherent()分配描述符内存。