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)。
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周期的末尾
3.2 PCM接口:更灵活的音频传输方式
PCM(Pulse Code Modulation)接口,名字听着很唬人。其实它和I2S本质上是同一类东西。我个人的理解是:PCM是I2S的「超集」。
3.2.1 与I2S的区别
PCM接口没有固定的声道映射规则。它更像一个「裸」的串行数据流。你可以自己定义每个时隙对应哪个声道。这就带来了很大的灵活性:
- 可以传输单声道、立体声、甚至多声道
- 数据位宽可以任意设置(8位、16位、24位、32位)
- 帧同步信号(FSYNC)可以是脉冲方式,也可以是电平方式
3.2.2 时序特点
PCM接口的时序有两种常见模式:
- 短帧同步模式:FSYNC是一个脉冲,宽度为一个SCK周期。数据在脉冲之后开始传输。
- 长帧同步模式: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 |
3.4 三种接口的对比与选型
说了这么多,到底什么时候用哪个?我根据自己的经验总结了一张表:
| 特性 | I2S | PCM | TDM |
|---|---|---|---|
| 声道数 | 2(立体声) | 1~2(可扩展) | 2~16+ |
| 引脚数 | 3(不含MCLK) | 3 | 3~4 |
| 灵活性 | 低(格式固定) | 中 | 高 |
| 兼容性 | 最好(几乎所有芯片都支持) | 较好 | 一般(高端芯片才支持) |
| 典型应用 | 耳机、音箱、手机 | 蓝牙音频、语音编解码 | 车载音响、多声道系统 |
选型建议:
- 做立体声产品:无脑选I2S。兼容性最好,调试最方便。
- 做蓝牙或语音产品:PCM接口更合适。因为它能灵活匹配数据包的边界。
- 做多声道系统:TDM是唯一选择。别想着用多个I2S拼凑,时序同步问题会让你崩溃的。
3.5 避坑指南
最后分享几个我踩过的坑:
- 时钟极性搞反:I2S和PCM都有多种时钟极性配置。我曾经把上升沿采样和下降沿采样搞反了,出来的声音像机器人说话。用示波器一看,数据采样点全在边沿上,能不怪吗?
- 主从模式不匹配:两个设备通信,必须一个做主一个做从。我见过有人把两个都配成主模式,结果时钟线上一团糟。
- 数据位宽不一致:发送端用24位,接收端配成16位。数据截断后,低8位丢了,声音失真。这个在调试时特别隐蔽,因为听起来「好像有点问题,但又说不出哪里不对」。
好了,数字音频接口这块就聊到这儿。记住一句话:时序图比文字靠谱,示波器比猜测靠谱。遇到音频问题,先拿示波器看波形,八成能找到问题所在。