第二章 嵌入式音频系统架构:音频编解码器、I2S/PCM接口、DMA传输、音频时钟管理
好,咱们进入正题。嵌入式音频系统,说白了就是让芯片能「听」和「说」的一套硬件流水线。很多刚入行的朋友以为只要把麦克风焊上去就能出声,结果一上电全是噪声——嗯,我当年也干过这事。
这一章我们拆开来看四个核心模块:编解码器怎么选、I2S/PCM怎么连、DMA怎么搬数据、时钟怎么管。搞懂这些,你的音频系统至少能跑起来不炸。
2.1 音频编解码器:芯片的「声带」和「耳朵」
编解码器(Codec)负责模数/数模转换。我习惯把它分成三类:
- 模拟Codec:内置ADC/DAC,直接接麦克风或喇叭。比如WM8960、TLV320AIC系列。
- 数字Codec:只有数字接口,需要外挂模拟前端。常见于高端音响。
- SoC内置Codec:省成本,但性能一般。比如ESP32自带的I2S接口。
选型时我一般看三个参数:
| 参数 | 说明 | 我的经验值 |
|---|---|---|
| 信噪比(SNR) | 决定底噪大小 | 低于85dB的芯片我基本不考虑 |
| 采样率支持 | 至少支持48kHz | 做Hi-Fi要上192kHz |
| 接口类型 | I2S还是PCM? | I2S更通用,PCM适合多通道 |
2.2 I2S/PCM接口:数字音频的「高速公路」
I2S和PCM,本质上都是串行总线。区别在哪?
- I2S:三根线——BCLK(位时钟)、LRCLK(左右声道时钟)、SD(数据)。数据在LRCLK变化时对齐。适合立体声。
- PCM:可以理解成I2S的变种。用帧同步信号代替LRCLK,支持多通道(比如TDM模式)。
我遇到过最坑的事:某次用STM32的I2S外设,发现LRCLK频率算错了。手册上说采样率48kHz时LRCLK应该是48kHz,但我忘了BCLK = 采样率 × 位深 × 通道数。结果BCLK设成了1.536MHz,LRCLK却配成了96kHz——声音直接变调。
BCLK = 采样率 × 位深 × 通道数
例如:48kHz × 16bit × 2通道 = 1.536MHz
接线时注意:I2S的SD线是双向的。发送数据用SD_OUT,接收用SD_IN。有些芯片把两根线合并成一根SDIO,这时候就要靠软件控制方向了。
2.3 DMA传输:让CPU喘口气
音频数据流是连续的。如果每个采样点都用CPU去搬,那CPU啥也别干了。DMA(直接存储器访问)就是干这个的——它自己把数据从内存搬到I2S发送寄存器,或者从I2S接收寄存器搬到内存。
配置DMA时,我一般关注三点:
- 传输方向:内存到外设(播放),还是外设到内存(录音)?
- 数据宽度:必须和I2S的位深一致。16位数据就用半字传输,32位就用字传输。
- 循环模式:音频流是连续的,必须开循环模式。否则DMA传完一轮就停了。
代码示例(伪代码,以STM32 HAL库为例):
// 配置I2S发送DMA
hdma_spi_tx.Instance = DMA2_Stream3;
hdma_spi_tx.Init.Channel = DMA_CHANNEL_0;
hdma_spi_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_spi_tx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_spi_tx.Init.Mode = DMA_CIRCULAR; // 循环模式,必须!
HAL_DMA_Init(&hdma_spi_tx);
__HAL_LINKDMA(&hi2s3, hdmatx, hdma_spi_tx);
2.4 音频时钟管理:一切的基础
音频对时钟抖动极其敏感。抖动大了,声音就「毛」了。我见过有人用MCU的内部RC振荡器做I2S时钟,结果高频段全是噪声——因为RC振荡器的抖动在纳秒级,而音频时钟要求皮秒级。
时钟管理我总结了三步走:
- 第一步:选时钟源。优先用外部晶振,比如12.288MHz或24.576MHz。这两个频率能整除常见的音频采样率(48kHz、96kHz等)。
- 第二步:配置PLL。如果MCU内部PLL够干净,也可以用。但记得看PLL的抖动指标。
- 第三步:分频。把主时钟分频得到BCLK和LRCLK。分频系数要整数,否则会产生频率偏差。
外部晶振 12.288MHz → PLL倍频到 98.304MHz → 分频得到 BCLK 1.536MHz → 再分频得到 LRCLK 48kHz
为什么用12.288MHz?你算算:98.304MHz ÷ 64 = 1.536MHz(BCLK),1.536MHz ÷ 32 = 48kHz(LRCLK)。64是BCLK分频系数,32是LRCLK分频系数——都是整数,完美。
最后说一句:时钟管理不是配完就完事的。上电后用示波器量一下BCLK的波形,看看上升沿干不干净。如果看到毛刺,多半是PCB走线太长或者阻抗不匹配。嗯,硬件工程师的活儿,咱们软件也得懂一点。
好了,这一章就到这。下一章我们讲音频数据流处理——怎么把PCM数据变成你想要的音效。