2. 声卡硬件基础
在深入Linux音频驱动源码之前,必须建立扎实的硬件基础。声卡并非单一芯片,而是由多个硬件模块通过特定总线互联而成的子系统。本章将拆解声卡的四大核心组件:数字音频接口(I2S/PCM)、音频编解码器(Codec)、DMA控制器以及音频数据格式,并阐明它们之间的协作关系。
2.1 数字音频接口:I2S与PCM
I2S(Inter-IC Sound)和PCM(Pulse Code Modulation)接口是SoC与外部Codec之间传输数字音频数据的标准串行总线。I2S由Philips(现NXP)定义,PCM接口则更通用,常用于电信和蓝牙音频。
2.1.1 I2S总线信号定义
I2S总线使用三根主要信号线,外加一根可选的MCLK(主时钟):
| 信号名称 | 方向 | 功能描述 |
|---|---|---|
| SCK / BCLK | 主机→从机 | 位时钟(Bit Clock),每个脉冲对应一个数据位。频率 = 采样率 × 位宽 × 通道数。 |
| WS / LRCK | 主机→从机 | 字选择(Word Select)或左右声道时钟。高电平表示左声道,低电平表示右声道(或反之)。频率 = 采样率。 |
| SD / DATA | 双向 | 串行数据线。在I2S标准模式下,数据在SCK的下降沿变化,上升沿被接收端锁存。 |
| MCLK | 主机→从机 | 主时钟(Master Clock),频率通常为采样率的256倍或512倍,用于Codec内部PLL和Δ-Σ调制器。 |
2.1.2 I2S数据格式与时序
I2S标准规定数据在WS切换后的第二个BCLK上升沿开始传输,MSB优先。下图展示了标准的I2S时序:
2.1.3 PCM接口与I2S的对比
PCM接口与I2S高度相似,主要区别在于帧同步(FSYNC)的宽度和位置。PCM通常使用短帧同步(一个BCLK周期),而I2S使用长帧同步(一个完整的字周期)。
| 特性 | I2S | PCM |
|---|---|---|
| 帧同步宽度 | 50% 占空比(一个完整字长) | 1个BCLK周期(短帧)或50%占空比(长帧) |
| 数据对齐 | 帧同步后延迟1个BCLK开始 | 帧同步边沿立即开始 |
| 典型应用 | 高保真音频Codec | 蓝牙音频、VoIP、电信 |
| 多通道支持 | 通常为2通道(立体声) | 支持TDM模式,可达8/16通道 |
dai-format属性时,务必确认Codec端支持的格式。格式不匹配会导致无声音或数据错位。
2.2 音频编解码器(Codec)工作原理
Codec(Coder-Decoder)是声卡的模拟前端,负责ADC(模数转换)和DAC(数模转换)。它内部集成了多个功能模块:
- ADC通道:将麦克风或线路输入的模拟信号转换为数字PCM数据。
- DAC通道:将数字PCM数据转换为模拟信号驱动耳机或扬声器。
- 混音器(Mixer):在数字域或模拟域混合多路音频流。
- 增益控制:可编程增益放大器(PGA),用于调节输入/输出音量。
- 滤波器:数字滤波器(如抽取滤波器、插值滤波器)和模拟抗混叠滤波器。
- 时钟管理:内部PLL,可从MCLK或BCLK生成所需的采样时钟。
2.2.1 Codec内部信号路径
下图展示了一个典型立体声Codec(如WM8960或TLV320AIC3x)的内部数据流:
2.3 DMA控制器与音频数据传输
DMA(Direct Memory Access)是音频驱动的核心性能保障。没有DMA,CPU必须逐字节搬运音频数据,导致高延迟和低效率。Linux音频驱动中,DMA用于在内存缓冲区和I2S控制器FIFO之间传输数据。
2.3.1 DMA传输模型
典型的音频DMA传输采用双缓冲(Ping-Pong Buffer)或环形缓冲区(Ring Buffer)机制:
- Ping-Pong Buffer:两个缓冲区交替使用。DMA填充一个缓冲区时,CPU处理另一个缓冲区。
- Ring Buffer:一个连续的循环缓冲区,DMA和CPU通过读写指针协作。Linux ALSA驱动默认使用此模型。
2.3.2 DMA控制器与I2S控制器的连接
下图展示了SoC内部DMA、I2S控制器和内存之间的数据流:
2.3.3 DMA描述符与链表
现代DMA控制器支持描述符链表(Descriptor Chain),允许驱动预先配置多个传输任务,DMA硬件自动按链表顺序执行,无需CPU干预。每个描述符包含:
| 描述符字段 | 说明 |
|---|---|
| 源地址 | 内存缓冲区地址(对于播放)或I2S FIFO地址(对于录音) |
| 目的地址 | I2S FIFO地址(播放)或内存缓冲区地址(录音) |
| 传输长度 | 以字节为单位的传输大小 |
| 下一个描述符指针 | 指向链表中的下一个描述符,NULL表示结束 |
| 控制标志 | 中断使能、传输方向、数据宽度等 |
dmaengine API与音频驱动交互。音频驱动调用dmaengine_prep_slave_sg()准备描述符,然后使用dmaengine_submit()提交。DMA完成回调用于更新ALSA的指针位置。
2.4 音频编解码器工作原理详解
理解Codec内部工作原理对于调试音频问题至关重要。本节聚焦ADC和DAC的核心机制。
2.4.1 ADC:从模拟到数字
音频ADC通常采用Δ-Σ(Delta-Sigma)调制技术,其工作流程如下:
- 抗混叠滤波:模拟信号先通过低通滤波器,去除高于奈奎斯特频率的成分。
- Δ-Σ调制:以极高采样率(如64倍或128倍过采样)对信号进行1位量化,产生高速1位流。
- 抽取滤波(Decimation):数字滤波器将1位流转换为多位的PCM数据,同时将采样率降低到目标值(如48kHz)。
- 数字增益与去直流:应用数字音量控制,并滤除直流偏移。
2.4.2 DAC:从数字到模拟
DAC是ADC的逆过程:
- 插值滤波(Interpolation):将PCM数据通过数字滤波器升采样到过采样率。
- Δ-Σ调制:将多位数转换为高速1位流。
- 模拟低通滤波:将1位流通过模拟滤波器还原为平滑的模拟波形。
- 输出驱动:通过PGA和输出缓冲器驱动耳机或扬声器。
2.4.3 Codec控制接口
Codec的寄存器配置通过I²C或SPI总线完成。驱动通过regmap框架读写Codec寄存器,控制以下关键参数:
| 寄存器类别 | 典型寄存器 | 作用 |
|---|---|---|
| 时钟控制 | 0x00: Clock Gen Control | 选择MCLK分频、PLL使能、采样率配置 |
| 接口格式 | 0x04: Digital Audio Interface | 设置I2S/PCM格式、位宽、主从模式 |
| 混音器 | 0x10: Mixer Control | 选择输入源、混合比例、静音控制 |
| 增益控制 | 0x14: Left PGA Volume | 设置输入/输出音量,范围通常为0~127 |
| 电源管理 | 0x20: Power Management | 独立控制ADC/DAC/混音器/输出级的电源开关 |
DAPM(Dynamic Audio Power Management)框架自动管理电源序列。
2.5 本章小结
声卡硬件基础是理解Linux音频驱动的基石。本章涵盖了:
- I2S/PCM接口:三线或四线串行总线,负责SoC与Codec之间的数字音频传输。驱动需正确配置BCLK/LRCK频率和时序。
- Codec内部架构:包含ADC、DAC、PGA、混音器和数字滤波器。通过I²C/SPI控制寄存器,驱动可配置增益、格式和电源状态。
- DMA传输:使用双缓冲或环形缓冲区实现内存与I2S FIFO之间的零CPU搬运。描述符链表支持批量传输,降低中断频率。
- Δ-Σ转换原理:过采样和噪声整形技术是高保真音频的核心,驱动无需直接操作,但理解其原理有助于排查噪声和失真问题。