ARM音频驱动DMA传输与ALSA框架调优实战 - 第4节
4.1 DMA控制器工作原理
直接存储器访问(DMA)是ARM音频系统中实现高效数据传输的核心硬件单元。它允许外设(如I2S控制器)与内存之间直接交换数据,无需CPU逐字节干预,从而将CPU从繁重的数据搬运任务中解放出来,专注于音频算法与上层应用逻辑。
4.1.1 DMA控制器核心组成
一个典型的ARM DMA控制器(如PL080、PL330或各SoC集成的定制DMA)包含以下关键模块:
| 模块 | 功能描述 | 音频场景作用 |
|---|---|---|
| 通道控制器 | 管理多个独立DMA通道,每个通道对应一条数据传输链路 | 通常使用1个通道用于播放(内存→I2S),1个通道用于录音(I2S→内存) |
| 源地址寄存器 | 存储数据源地址(内存地址或外设FIFO地址) | 播放时指向音频缓冲区;录音时指向I2S RX FIFO |
| 目的地址寄存器 | 存储数据目标地址 | 播放时指向I2S TX FIFO;录音时指向内存缓冲区 |
| 传输计数寄存器 | 记录待传输的数据单元数量(通常以字为单位) | 决定每次DMA突发传输的音频样本数 |
| 控制与状态寄存器 | 配置传输方向、宽度、突发大小,并反映传输完成/错误状态 | 配置16位/32位音频样本宽度,设置中断使能 |
| 总线接口单元 | 通过AHB/AXI总线矩阵访问内存和外设寄存器 | 确保音频数据在系统总线上的优先级与带宽 |
关键概念: DMA控制器本身是一个总线主机(Bus Master),它可以在不经过CPU的情况下直接发起读写事务。在ARM系统中,DMA通常通过AHB或AXI总线与内存和外设连接。
4.1.2 DMA传输流程(内存到外设)
以音频播放为例,DMA将内存中的PCM样本数据传输到I2S发送FIFO,完整流程如下:
- CPU初始化: 配置DMA通道的源地址(音频缓冲区)、目的地址(I2S TX FIFO)、传输宽度(16位/32位)、突发大小(4/8字)和传输计数。
- CPU使能DMA: 设置通道使能位,DMA控制器进入就绪状态。
- 外设请求: I2S发送FIFO空余位置达到阈值(如半空),I2S控制器向DMA发送硬件握手信号(DMA请求线)。
- DMA响应: DMA控制器仲裁后,通过总线读取内存中的音频数据。
- 数据传输: DMA将读取的数据写入I2S TX FIFO,同时更新源地址和传输计数。
- 循环/完成: 若为循环模式,传输计数归零后自动重载;若为单次模式,触发完成中断通知CPU。
性能要点: 突发传输(Burst Transfer)可以显著提高总线利用率。例如,一次突发读取4个32位字,比4次单字读取减少约60%的总线仲裁开销。在音频驱动中,建议将突发大小配置为与I2S FIFO深度匹配。
4.2 内存到外设与外设到内存传输
音频DMA传输的两个基本方向对应着播放和录音两种场景。虽然硬件原理对称,但在驱动实现和性能调优上存在重要差异。
4.2.1 传输方向对比
| 特性 | 内存→外设(播放) | 外设→内存(录音) |
|---|---|---|
| 数据流 | 内存缓冲区 → DMA → I2S TX FIFO | I2S RX FIFO → DMA → 内存缓冲区 |
| 源地址类型 | 内存地址(递增) | 外设FIFO地址(固定) |
| 目的地址类型 | 外设FIFO地址(固定) | 内存地址(递增) |
| 地址更新规则 | 源地址递增,目的地址固定 | 源地址固定,目的地址递增 |
| CPU干预时机 | 缓冲区空时(underrun) | 缓冲区满时(overrun) |
| 典型中断 | 传输完成/半完成中断 | 传输完成/半完成中断 |
常见陷阱: 在录音方向,如果DMA读取外设FIFO的速度慢于I2S接收速度,将导致FIFO溢出(Overrun),丢失音频数据。必须确保DMA的响应延迟和突发大小能够匹配I2S的采样率。例如,48kHz/16位立体声每秒产生192KB数据,DMA必须在每个采样间隔内完成一次传输。
4.2.2 传输配置代码示例
以下是在Linux内核中配置DMA传输方向的典型代码片段(基于dmaengine API):
/* 播放方向:内存到外设 */
struct dma_slave_config playback_config = {
.direction = DMA_MEM_TO_DEV,
.src_addr = (dma_addr_t)audio_buffer_phys, /* 内存缓冲区物理地址 */
.dst_addr = i2s_regs_phys + I2S_TX_FIFO, /* I2S发送FIFO物理地址 */
.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, /* 32位音频样本 */
.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
.src_maxburst = 4, /* 每次突发4个字 */
.dst_maxburst = 4,
.slave_id = I2S_TX_DMA_REQ, /* 硬件请求线ID */
};
/* 录音方向:外设到内存 */
struct dma_slave_config capture_config = {
.direction = DMA_DEV_TO_MEM,
.src_addr = i2s_regs_phys + I2S_RX_FIFO, /* I2S接收FIFO物理地址 */
.dst_addr = (dma_addr_t)capture_buffer_phys, /* 录音缓冲区物理地址 */
.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
.src_maxburst = 4,
.dst_maxburst = 4,
.slave_id = I2S_RX_DMA_REQ,
};
4.3 单次传输与循环传输(Ring Buffer)
DMA传输模式的选择直接影响音频流的连续性和CPU负载。单次传输适用于一次性数据搬运,而循环传输是音频驱动的核心机制。
4.3.1 单次传输模式
单次传输(Single Transfer)模式下,DMA完成预设数量的数据传输后自动停止,并触发完成中断。CPU需要在中断服务程序中重新配置并启动下一次传输。
- 优点: 实现简单,适合短数据块传输(如控制命令、状态读取)。
- 缺点: 每次传输结束都需要CPU重新配置,中断频率高,不适合连续音频流。
- 音频应用: 仅用于非实时音频处理,如播放提示音、按键音等短片段。
4.3.2 循环传输模式(Ring Buffer)
循环传输(Circular Transfer / Ring Buffer)是音频驱动的标准模式。DMA在到达缓冲区末尾后自动回绕到起始地址,形成无限循环的数据流。
| 特性 | 单次传输 | 循环传输 |
|---|---|---|
| 地址回绕 | 无,传输结束后停止 | 自动回绕到起始地址 |
| CPU干预 | 每次传输结束都需要 | 仅在半满/完成时更新数据 |
| 中断频率 | 高(每次传输完成) | 低(可配置为半缓冲完成) |
| 连续性 | 不连续,有间隙 | 连续,无间隙 |
| 缓冲区管理 | 简单 | 需要环形缓冲区指针管理 |
| 音频适用性 | 不推荐 | 标准方案 |
Ring Buffer核心机制: DMA控制器内部维护一个缓冲区大小寄存器(或通过LLI链表实现)。当传输地址达到缓冲区末尾时,硬件自动将地址寄存器重置为缓冲区起始地址,同时传输计数寄存器重新加载。整个过程无需CPU参与,保证了音频流的绝对连续性。
4.3.3 循环传输的SVG架构图
4.4 硬件同步与软件触发
DMA传输的启动和同步方式决定了音频数据流的实时性。硬件同步模式利用外设的硬件请求信号自动触发DMA传输,而软件触发模式则由CPU通过写寄存器手动启动传输。
4.4.1 硬件同步模式(Hardware Synchronization)
在硬件同步模式下,DMA传输由外设发出的硬件请求信号触发。这是音频驱动的标准工作方式。
- 触发源: I2S控制器在FIFO达到预设阈值时,通过专用DMA请求线(DMA Request Line)向DMA控制器发送脉冲信号。
- 传输粒度: 每次硬件请求触发一次突发传输(Burst),传输大小由配置的burst size决定。
- 实时性: 外设的采样时钟直接决定了DMA传输的节奏,保证音频数据的实时性。
- CPU负载: 极低,CPU仅在缓冲区半满/完成时处理数据更新。
硬件同步的关键配置: 在dma_slave_config中设置
slave_id字段,该ID对应SoC数据手册中定义的DMA请求线编号。例如,在Samsung Exynos平台上,I2S0的TX DMA请求线通常为ID 5,RX为ID 6。
4.4.2 软件触发模式(Software Trigger)
软件触发模式下,CPU通过写DMA控制寄存器手动启动传输。传输完成后,CPU需要再次写寄存器启动下一次传输。
- 触发源: CPU写DMA通道的使能寄存器或软件触发寄存器。
- 传输粒度: 一次软件触发可以启动整个传输任务(直到传输计数归零)。
- 实时性: 依赖CPU的响应速度,存在不确定性延迟。
- CPU负载: 高,每次传输都需要CPU参与。
软件触发的局限性: 在音频场景中,软件触发无法保证与I2S位时钟的精确同步。如果CPU因中断延迟未能及时触发下一次DMA传输,将导致音频流中断(XRUN)。因此,软件触发仅用于非实时或低采样率的音频测试场景。
4.4.3 硬件同步与软件触发对比
| 对比维度 | 硬件同步 | 软件触发 |
|---|---|---|
| 触发方式 | 外设硬件请求信号自动触发 | CPU写寄存器手动触发 |
| 同步时钟源 | I2S位时钟/帧时钟 | CPU时钟/定时器 |
| 传输延迟 | 确定,与采样时钟同步 | 不确定,受中断延迟影响 |
| CPU负载 | 极低 | 高 |
| 适用场景 | 实时音频播放/录音 | 测试、调试、非实时传输 |
| XRUN风险 | 低(配置正确时) | 高 |
4.4.4 硬件同步的SVG时序图
4.5 本章小结
核心要点回顾:
- DMA控制器通过通道、地址寄存器、计数寄存器和总线接口实现内存与外设之间的直接数据传输。
- 内存到外设(播放)和外设到内存(录音)在地址更新规则上对称,但驱动配置时需注意方向参数。
- 循环传输(Ring Buffer)是音频驱动的基石,通过硬件地址回绕实现无中断的连续音频流。
- 硬件同步模式利用I2S的采样时钟自动触发DMA传输,是保证音频实时性的关键机制。
- 软件触发仅适用于测试场景,在正式音频驱动中应始终使用硬件同步模式。