2、音频硬件基础:数字音频接口(I2S、PCM、TDM)、采样率与位深、音频编解码器工作原理
好,我们正式开始第二讲。上一章我们聊了音频系统的大框架,这一章得把底层的硬件基础夯实了。说白了,你如果不懂I2S怎么传数据,不懂采样率为什么是44.1kHz而不是50kHz,那后面看DAPM的代码会非常痛苦。我自己带新人时,发现他们卡住的地方,十有八九都是这里的基础没打牢。
2.1 数字音频接口:I2S、PCM、TDM
先问个问题:音频数据在芯片之间是怎么流动的?比如Codec和SoC之间。答案就是通过数字音频接口。最常见的三种:I2S、PCM(这里指脉冲编码调制接口,不是音频编码格式)、TDM。
2.1.1 I2S(Inter-IC Sound)
I2S是飞利浦在80年代搞出来的标准,现在几乎成了嵌入式音频的标配。它用三根线:
- BCLK(位时钟):每个脉冲对应一个数据位。频率 = 采样率 × 位深 × 声道数。
- LRCK(帧时钟/左右声道时钟):高低电平切换代表左右声道。频率 = 采样率。
- SDATA(串行数据):二进制音频数据,通常是二进制补码。
举个例子:44.1kHz采样率、16位、立体声。BCLK频率就是 44.1k × 16 × 2 = 1.4112 MHz。LRCK就是44.1kHz。嗯,这里要注意,I2S标准规定数据在BCLK的下降沿变化,在上升沿采样。我早期调试时没注意这个时序,结果左右声道数据串了,查了整整两天。
关键点:I2S的LRCK变化比数据提前一个BCLK周期。这是为了接收端能准确识别声道起始。很多国产芯片不严格遵循这个,导致兼容性问题。
2.1.2 PCM接口
PCM接口和I2S非常像,也是三根线。区别在于帧同步信号(FSYNC)的占空比。I2S的LRCK是50%占空比,而PCM接口的FSYNC通常是一个短脉冲,宽度只有一个BCLK周期。
我个人习惯把PCM接口看作「简化版I2S」。它在一些老式DSP和蓝牙音频模块上很常见。比如CSR的蓝牙芯片,默认就是PCM接口。我曾经在一个项目中,把I2S的Codec接到了PCM接口的蓝牙模块上,结果死活不出声。后来发现是帧同步的极性反了——PCM的FSYNC通常是高电平有效,而I2S的LRCK是低电平左声道。这种坑,你光看datasheet是看不出来的,得拿逻辑分析仪抓波形。
2.1.3 TDM(时分复用)
TDM就是把多个声道的数据塞到一根数据线上。比如8声道音频,用TDM模式,一根SDATA线就够了。BCLK频率会相应提高。
TDM在专业音频设备和车载音响里用得很多。你想想看,一个车载功放要处理8个甚至16个声道,如果每个声道都用独立的I2S,那线束得多恐怖?TDM一根线搞定。
TDM的配置参数比I2S多:
- 槽位(Slot)数量:每个声道占一个槽位。
- 槽位宽度:每个槽位多少位。常见16位或32位。
- 帧同步模式:短帧(一个BCLK脉冲)或长帧(一个BCLK周期的高电平)。
经验之谈:调试TDM时,先确认槽位宽度。很多Codec要求槽位宽度等于位深,但有些DSP要求槽位宽度固定为32位。我遇到过最坑的一次,是Codec的槽位宽度设成了24位,但SoC的TDM控制器只支持16或32位,中间差了8位,数据全错位了。
2.2 采样率与位深
这两个参数决定了音频的「质量」。但很多人只记住了数字,不理解背后的物理意义。
2.2.1 采样率
采样率就是每秒采集多少个样本点。根据奈奎斯特定理,采样率必须大于信号最高频率的两倍,才能无失真重建。
人耳能听到的频率范围是20Hz-20kHz。所以理论上40kHz采样就够了。为什么CD标准是44.1kHz?这里面有个历史原因:早期数字录音用的是录像带,录像带的扫描频率和电视制式有关。NTSC制式下,一个场周期能存245个样本,每场有3个样本用于同步,剩下245-3=242个有效样本。帧率是60Hz,所以 242 × 60 = 14520 样本/秒?不对,这是单声道。立体声要翻倍,再考虑一些纠错开销,最后定在了44.1kHz。嗯,这个数字就是这么来的,不是拍脑袋定的。
常见的采样率:
| 采样率 | 典型应用 |
|---|---|
| 8 kHz | 电话语音 |
| 16 kHz | VoIP、语音识别 |
| 44.1 kHz | CD、MP3 |
| 48 kHz | DVD、电影 |
| 96 kHz / 192 kHz | 高解析度音频、专业录音 |
注意:采样率转换(SRC)是有损的。如果系统里同时有44.1kHz和48kHz的音频流,最好在硬件层面做SRC,不要用软件做。软件SRC的延迟和CPU开销都很大。
2.2.2 位深
位深决定了动态范围。每个位大约贡献6dB的动态范围。16位就是96dB,24位就是144dB。
为什么16位就够了?因为人耳在安静环境下的动态范围也就120dB左右,96dB已经能覆盖大部分听音场景了。但为什么还要24位?因为录音和后期处理需要余量。你想想看,录音时如果峰值刚好到0dBFS,稍微一个瞬态就削波了。24位给了你更多的头尾空间。
我在做车载音频项目时,遇到过一个问题:播放16位44.1kHz的音乐,底噪特别大。后来发现是Codec的输入位深设成了24位,而SoC输出的是16位数据,低8位全是0。Codec把0当作有效数据放大了,底噪就出来了。解决办法是把SoC的输出位深也改成24位,或者让Codec的输入位深匹配16位。
2.3 音频编解码器工作原理
音频编解码器(Audio Codec),说白了就是ADC和DAC的集合体,再加上一些模拟和数字处理模块。
2.3.1 基本架构
一个典型的Codec内部包含:
- ADC通道:模拟信号 → 数字信号。用于麦克风输入、线路输入。
- DAC通道:数字信号 → 模拟信号。用于耳机输出、扬声器输出。
- 混音器(Mixer):多路信号混合。
- 增益控制:模拟增益和数字增益。
- 滤波器:抗混叠滤波器、去加重滤波器等。
- 数字接口:I2S/PCM/TDM控制器。
- 控制接口:I2C或SPI,用于配置寄存器。
2.3.2 信号路径
以播放为例(DAC路径):
- SoC通过I2S接口把数字音频数据发给Codec。
- Codec的数字接口接收数据,存入FIFO。
- 数字滤波器对数据进行插值和滤波(升采样)。
- DAC将数字信号转换为模拟信号。
- 模拟滤波器平滑波形,去除高频噪声。
- 经过音量控制和输出放大器,送到耳机或扬声器。
录音路径(ADC路径)就是反过来:模拟信号进来,经过抗混叠滤波器、ADC转换、数字滤波、I2S输出。
核心概念:Codec的「通路」(Pathway)或「路由」(Routing)。你配置Codec,本质上就是在配置信号从哪个输入走到哪个输出,中间经过哪些处理模块。DAPM就是自动管理这些通路的开关和功耗。
2.3.3 常见Codec寄存器
以WM8960为例(我项目里用得比较多的一款):
| 寄存器地址 | 功能 |
|---|---|
| 0x00 | 左声道输入音量 |
| 0x02 | 右声道输入音量 |
| 0x04 | 左声道输出音量 |
| 0x06 | 右声道输出音量 |
| 0x08 | 音频接口控制(I2S格式、位深等) |
| 0x0A | 时钟控制(采样率、MCLK分频) |
| 0x2C | DAC控制(去加重、静音等) |
配置Codec的流程一般是:上电 → 复位 → 配置时钟 → 配置音频接口格式 → 配置通路 → 设置音量 → 解除静音。顺序错了可能不出声,甚至烧坏喇叭。我曾经在调试一个项目时,先解除了静音再配置通路,结果一个巨大的pop声差点把测试耳机震坏。从那以后,我写Codec初始化代码时,一定把静音放在最后一步。
2.3.4 时钟架构
Codec需要多个时钟:
- MCLK(主时钟):Codec内部数字电路的主时钟。通常是采样率的整数倍,比如256fs、384fs、512fs。fs就是采样率。
- BCLK(位时钟):I2S接口的位时钟。
- LRCK(帧时钟):I2S接口的帧时钟。
MCLK和BCLK之间必须有固定的倍数关系。比如MCLK=12.288MHz,采样率48kHz,那么MCLK/fs = 256。BCLK = 48k × 32 × 2 = 3.072MHz。MCLK/BCLK = 4。如果这个比例不对,Codec内部的PLL锁不住,就会产生时钟抖动,声音会失真。
避坑指南:我曾经在一个项目里,SoC的MCLK输出是12MHz,而Codec要求12.288MHz。差了2.4%,Codec的PLL勉强能锁住,但输出的音频有明显的「沙沙」声。后来换了一颗晶振才解决。所以,时钟精度很重要,尽量用整数倍关系。
好了,这一章的内容就到这里。数字音频接口、采样率位深、Codec工作原理,这三块是音频驱动开发的基石。下一章我们正式进入ASoC框架,看看Linux是怎么把这些硬件抽象成软件组件的。