3、音频编解码器选型:主流Codec芯片对比与I2S/PCM接口详解

做音频系统这么多年,选Codec芯片这事儿,我踩过的坑真不少。说白了,选对一颗Codec,项目就成功了一半。今天咱们就聊聊三款主流芯片——WM8960、TLV320AIC3204、ES8311,顺便把I2S和PCM接口掰开揉碎了讲清楚。

3.1 三款主流Codec芯片对比

先说说我个人的选型习惯。我一般会先看项目需求:是消费级产品还是工业级?功耗要求多严?需要几个麦克风?嗯,这些条件一列,芯片范围就缩小了。

参数 WM8960 TLV320AIC3204 ES8311
厂商 Wolfson (现Cirrus Logic) TI (德州仪器) Everest Semiconductor
接口类型 I2S / PCM I2S / PCM / TDM I2S / PCM
采样率 8kHz ~ 96kHz 8kHz ~ 192kHz 8kHz ~ 96kHz
信噪比(SNR) 98dB (ADC) / 98dB (DAC) 92dB (ADC) / 100dB (DAC) 93dB (ADC) / 95dB (DAC)
功耗 约 10mW (播放) 约 8mW (播放) 约 5mW (播放)
内置DSP 有 (MiniDSP)
典型应用 便携音箱、车载 降噪耳机、智能设备 低功耗IoT、手表

3.2 各芯片实战经验

3.2.1 WM8960:经典中的经典

WM8960是我用得最多的一款。为什么?因为它皮实。我记得有一次做车载项目,环境温度高到离谱,其他芯片都开始跑调了,WM8960愣是稳如老狗。

它的特点很鲜明:

  • 双声道D类功放:直接驱动喇叭,省掉外部功放芯片
  • 内置PLL:时钟抖动容忍度高,省心
  • 3D增强功能:听感调校空间大
注意:WM8960的I2C地址是0x1A(7位地址),但有些开发板默认是0x1B。我当初就被这个坑过——读不到寄存器,查了半天才发现是地址跳线没焊对。

3.2.2 TLV320AIC3204:DSP玩家的最爱

如果你要做降噪或者语音增强,AIC3204是首选。它内置的MiniDSP可以跑一些简单的滤波算法,不用额外加MCU。

我有个项目要做双麦克风降噪,用AIC3204的MiniDSP实现了自适应滤波器,效果还不错。不过要注意:

  • MiniDSP的编程需要TI的PurePath Studio工具,学习曲线有点陡
  • 寄存器配置比WM8960复杂,建议用TI提供的脚本生成工具
小技巧:AIC3204的PLL配置有个公式:f_PLL = f_MCLK × (R × J.D) / P。其中J.D是小数分频系数。我习惯先算好整数部分J,再微调小数部分D,这样能避免时钟失锁。

3.2.3 ES8311:低功耗小钢炮

ES8311是后起之秀,主打低功耗。做智能手表或者TWS耳机时,我经常推荐它。功耗只有WM8960的一半,但音质也不差。

它的亮点:

  • 超低功耗:播放模式5mW,待机模式不到1μW
  • 封装小:QFN-28,适合空间受限的产品
  • 内置电荷泵:单电源供电即可,省掉负压电路

不过要注意,ES8311的I2S时序要求比较严格。我曾经遇到过BCLK频率不准导致声音断续的问题,后来发现是MCU的I2S时钟分频器配置错了。

3.3 I2S与PCM接口详解

这两个接口是Codec和主控通信的桥梁。很多新手搞混它们,其实说白了,I2S是PCM的一种特殊格式。

3.3.1 I2S接口

I2S(Inter-IC Sound)是飞利浦定义的音频总线标准。它有三根主要信号线:

  • BCLK:位时钟,每个bit一个脉冲
  • LRCK:左右声道选择,频率等于采样率
  • SDATA:串行数据

时序关系是这样的:

BCLK:  __    __    __    __    __    __    __    __
      |  |__|  |__|  |__|  |__|  |__|  |__|  |__|
LRCK:  |_____________|_____________|_____________|
      左声道         右声道         左声道
SDATA: [MSB ... LSB] [MSB ... LSB] [MSB ... LSB]

I2S有个特点:数据在BCLK的下降沿变化,在上升沿采样。嗯,这个细节很重要,我见过有人把极性搞反,结果数据全错位了。

3.3.2 PCM接口

PCM(Pulse Code Modulation)接口比I2S更灵活。它支持时分复用(TDM),可以同时传输多个声道。

PCM和I2S的主要区别:

  • 帧同步信号:I2S用LRCK,PCM用FSYNC(帧同步脉冲)
  • 数据对齐:I2S数据在LRCK变化后延迟一个BCLK,PCM数据与FSYNC对齐
  • 声道数:I2S固定双声道,PCM可以扩展到8声道甚至更多
选型建议:如果只是立体声播放,I2S就够了。如果需要多声道(比如5.1环绕声)或者要接多个Codec,用PCM的TDM模式更合适。

3.3.3 时钟配置避坑指南

我曾经在一个项目里,Codec死活不出声。查了三天,最后发现是MCLK频率不对。这里给大家总结一下时钟配置的要点:

  1. MCLK必须是BCLK的整数倍:通常MCLK = 256 × 采样率,或者128×、512×
  2. BCLK = 采样率 × 位宽 × 声道数:比如44.1kHz、16bit、立体声,BCLK = 44.1k × 16 × 2 = 1.4112MHz
  3. LRCK = 采样率:这个最简单,但要注意左右声道极性
警告:有些Codec支持自动检测MCLK频率,但我不建议依赖这个功能。最好在驱动里显式配置PLL分频系数,否则换一颗晶振就可能出问题。

3.4 驱动开发要点

最后聊聊驱动。Linux下Codec驱动通常用ASoC(ALSA System on Chip)框架。核心是注册一个snd_soc_codec_driver结构体:

static struct snd_soc_codec_driver soc_codec_dev_wm8960 = {
    .probe = wm8960_probe,
    .remove = wm8960_remove,
    .suspend = wm8960_suspend,
    .resume = wm8960_resume,
    .controls = wm8960_snd_controls,
    .num_controls = ARRAY_SIZE(wm8960_snd_controls),
    .dapm_widgets = wm8960_dapm_widgets,
    .num_dapm_widgets = ARRAY_SIZE(wm8960_dapm_widgets),
    .dapm_routes = wm8960_dapm_routes,
    .num_dapm_routes = ARRAY_SIZE(wm8960_dapm_routes),
};

这里要注意DAPM(动态音频电源管理)的配置。我刚开始写驱动时,DAPM路由配错了,导致播放时喇叭没声音,但耳机有声音。查了半天才发现是路径没打通。

嗯,今天就聊到这儿。下一章咱们讲麦克风阵列的硬件设计,到时候再细聊。