3、数字音频接口:I2S、PCM、TDM接口协议详解与对比

做嵌入式音频开发,打交道最多的就是数字音频接口。我刚开始接触这块时,也被I2S、PCM、TDM这几个名字搞得有点晕。说白了,它们都是用来传输数字音频数据的,但适用场景和细节差别不小。今天咱们就好好捋一捋。

3.1 I2S接口:最经典的立体声音频总线

I2S(Inter-IC Sound)是飞利浦公司在80年代提出的。到现在,它依然是立体声音频传输的标配。我个人习惯把它叫做「音频界的I2C」——简单、可靠、到处都在用。

3.1.1 信号线定义

I2S总线只需要三根核心信号线:

  • SCK(串行时钟):也叫位时钟(BCLK)。每个脉冲对应一个数据位。频率 = 采样率 × 位深 × 声道数。
  • WS(字选择):也叫帧时钟(LRCK)。用来区分左右声道。高电平通常是右声道,低电平是左声道(也有反的,看芯片手册)。
  • SD(串行数据):音频数据就靠这根线传。可以是输入(SDI)或输出(SDO)。
小提示:有些芯片还会多一根MCLK(主时钟)。我遇到过不少新手以为MCLK是I2S的标配,其实不是。MCLK是给内部Σ-Δ调制器用的,I2S协议本身不需要它。

3.1.2 数据格式

I2S的数据格式有个特点:数据在WS翻转后的第二个时钟沿开始传输。为什么这样设计?我猜是为了给DAC留出准备时间。你想想看,如果WS一变就开始传数据,接收端可能还没反应过来。

标准的I2S数据格式如下:

// 以16位数据为例,左声道对齐
WS:   ____|‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾|________________|‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
SCK: _|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_
SD:  X MSB ... LSB X X MSB ... LSB X
     ← 左声道数据 →   ← 右声道数据 →

这里要注意:数据是MSB先传的。而且数据位宽可以小于SCK周期数。比如你用32位SCK传24位数据,多余的位会补0。

3.1.3 常见变体

I2S其实有好几种「方言」:

  • 标准I2S:数据在WS变化后延迟1个SCK开始
  • 左对齐(Left-Justified):数据在WS变化后立即开始,没有延迟
  • 右对齐(Right-Justified):数据对齐到SCK周期的末尾
注意:我曾经在一个项目里被这个坑过——CODEC芯片用的是左对齐,但MCU的I2S外设默认是标准I2S。结果出来的声音全是噪声。排查了整整两天才发现是格式不匹配。所以拿到新芯片,第一件事就是看数据手册里的时序图!

3.2 PCM接口:更灵活的音频传输方式

PCM(Pulse Code Modulation)接口,名字听着很唬人。其实它和I2S本质上是同一类东西。我个人的理解是:PCM是I2S的「超集」

3.2.1 与I2S的区别

PCM接口没有固定的声道映射规则。它更像一个「裸」的串行数据流。你可以自己定义每个时隙对应哪个声道。这就带来了很大的灵活性:

  • 可以传输单声道、立体声、甚至多声道
  • 数据位宽可以任意设置(8位、16位、24位、32位)
  • 帧同步信号(FSYNC)可以是脉冲方式,也可以是电平方式

3.2.2 时序特点

PCM接口的时序有两种常见模式:

  1. 短帧同步模式:FSYNC是一个脉冲,宽度为一个SCK周期。数据在脉冲之后开始传输。
  2. 长帧同步模式:FSYNC保持一个完整的帧周期。类似I2S的WS信号。
// 短帧同步模式示例(单声道,16位数据)
FSYNC: _|‾|________________________|‾|________
SCK:   _|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_
SD:    X MSB ... LSB X X X X X X X X X X X X X

我在做蓝牙音频项目时,就特别喜欢用PCM接口的短帧模式。因为蓝牙音频数据包是突发的,短帧同步能更好地匹配这种传输特性。

3.3 TDM接口:多声道音频的终极方案

TDM(Time Division Multiplexing)接口,说白了就是「时分复用」。它把多个声道的数据塞进同一根数据线里,每个声道分到一个固定的时间片。

3.3.1 为什么需要TDM?

你想想看,如果用I2S做8声道音频,需要4对I2S总线。这太浪费引脚了。TDM接口只用一根数据线就能搞定。我做过一个车载音响项目,用了TDM接口,一根SD线传了8个声道的数据,省下来的GPIO都拿去接按键和LED了。

3.3.2 帧结构

TDM的帧结构很清晰:

// 4声道TDM,每声道16位数据
FSYNC: _|‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾|_
SCK:   _|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_
SD:    [声道0 16位] [声道1 16位] [声道2 16位] [声道3 16位]

每个时隙(Slot)的长度可以配置。常见的有16位、24位、32位。时隙数就是声道数。帧同步信号通常在每个帧的开始处有一个脉冲。

3.3.3 配置要点

配置TDM接口时,有几个参数必须搞清楚:

参数 说明 常见值
帧长 一个完整帧包含的SCK周期数 64、128、256
时隙数 每帧包含的声道数 2、4、8、16
时隙宽度 每个声道占用的SCK周期数 16、24、32
数据偏移 数据在时隙内的起始位置 0、1、2
关键点:帧长必须 ≥ 时隙数 × 时隙宽度。如果帧长大于这个乘积,多余的位置会填充0(或者保持高阻,取决于芯片设计)。

3.4 三种接口的对比与选型

说了这么多,到底什么时候用哪个?我根据自己的经验总结了一张表:

特性 I2S PCM TDM
声道数 2(立体声) 1~2(可扩展) 2~16+
引脚数 3(不含MCLK) 3 3~4
灵活性 低(格式固定)
兼容性 最好(几乎所有芯片都支持) 较好 一般(高端芯片才支持)
典型应用 耳机、音箱、手机 蓝牙音频、语音编解码 车载音响、多声道系统

选型建议:

  • 做立体声产品:无脑选I2S。兼容性最好,调试最方便。
  • 做蓝牙或语音产品:PCM接口更合适。因为它能灵活匹配数据包的边界。
  • 做多声道系统:TDM是唯一选择。别想着用多个I2S拼凑,时序同步问题会让你崩溃的。
我的经验:如果你不确定选哪个,先看主控芯片支持什么。有些MCU的I2S外设其实也支持PCM和TDM模式。比如STM32的SAI外设,一个模块就能搞定三种模式。嗯,选芯片时多看看数据手册的「Audio Interface」章节,能省不少事。

3.5 避坑指南

最后分享几个我踩过的坑:

  • 时钟极性搞反:I2S和PCM都有多种时钟极性配置。我曾经把上升沿采样和下降沿采样搞反了,出来的声音像机器人说话。用示波器一看,数据采样点全在边沿上,能不怪吗?
  • 主从模式不匹配:两个设备通信,必须一个做主一个做从。我见过有人把两个都配成主模式,结果时钟线上一团糟。
  • 数据位宽不一致:发送端用24位,接收端配成16位。数据截断后,低8位丢了,声音失真。这个在调试时特别隐蔽,因为听起来「好像有点问题,但又说不出哪里不对」。

好了,数字音频接口这块就聊到这儿。记住一句话:时序图比文字靠谱,示波器比猜测靠谱。遇到音频问题,先拿示波器看波形,八成能找到问题所在。