I2S协议详解:时序、格式、主从与采样率计算
I2S,全称 Inter-IC Sound,说白了就是数字音频设备之间传音频数据的串行总线协议。飞利浦公司在 80 年代搞出来的,到现在还是嵌入式音频领域的事实标准。你想想看,STM32 跟 WM8960 这类 Codec 芯片通信,十有八九走的就是 I2S。
我个人习惯把 I2S 理解成「三线一钟」——三条数据线加一个时钟。嗯,这里要注意,有些场景下还会多一条 MCLK,后面我会讲到。
I2S 总线时序:三根线怎么跑数据?
标准的 I2S 总线就三根核心信号线:
- SCK(串行时钟,也叫 BCLK)—— 每一位数据对应一个脉冲
- WS(字选择,也叫 LRCLK)—— 左右声道切换,低电平左声道,高电平右声道
- SD(串行数据)—— 音频数据按位传输
时序上有个关键点:数据在 SCK 的上升沿被采样,WS 在 SCK 的下降沿变化。我在项目中遇到过有人把 SCK 极性搞反,结果出来的声音全是噪声,查了半天才发现是时钟相位配置错了。
核心时序规则:
- WS 变化发生在 SCK 下降沿
- 数据最高位(MSB)在 WS 变化后的第二个 SCK 上升沿开始传输
- 数据在 SCK 上升沿被锁存
为什么会这样设计?说白了就是为了让接收端有足够的时间准备。WS 先变,告诉芯片「下一个是左声道还是右声道」,然后过一个时钟周期才开始传数据,这样接收端就能从容应对。
飞利浦格式 vs 左对齐格式:到底差在哪?
这两个格式是 I2S 协议里最常见的变体。我刚开始做音频驱动时,经常把这两个搞混,后来画了个时序图才彻底明白。
| 对比项 | 飞利浦格式(标准 I2S) | 左对齐格式 |
|---|---|---|
| 数据起始位置 | WS 变化后的第 2 个 SCK 上升沿 | WS 变化后的第 1 个 SCK 上升沿 |
| MSB 对齐方式 | 延迟 1 个 SCK 周期 | 立即对齐到 WS 边沿 |
| 兼容性 | 最广泛,几乎所有 Codec 都支持 | 部分 DSP 和 Codec 使用 |
| 典型应用 | WM8960、CS43L22 等通用音频 Codec | 某些 DSP 处理器、老式音频芯片 |
用一句话总结:飞利浦格式比左对齐格式晚了一个 SCK 周期才开始传数据。WM8960 的数据手册里明确写了它支持这两种格式,但默认推荐用飞利浦格式。我建议你刚开始调试时先用飞利浦格式,踩坑少。
个人经验: 我曾经在调试一块第三方音频模块时,怎么调都没声音,后来用逻辑分析仪抓了 WS 和 SD 的时序,发现 Codec 配置的是左对齐,而 STM32 配的是飞利浦格式。改过来之后,声音就出来了。所以,先确认格式匹配,再查其他问题。
主从模式配置:谁给时钟?
I2S 通信里,主从模式决定了谁负责产生 SCK 和 WS 时钟信号。
- 主机模式:STM32 产生 SCK 和 WS,Codec 作为从机接收时钟
- 从机模式:Codec 产生时钟,STM32 作为从机接收
在 STM32 + WM8960 这个组合里,我个人习惯把 STM32 配成主机,WM8960 配成从机。原因很简单:STM32 的时钟树好控制,你想生成 44.1kHz 还是 48kHz,通过 PLL 分频就能搞定。WM8960 内部虽然也有 PLL,但配置起来相对麻烦。
注意: 主从模式必须匹配。如果两边都配成主机,时钟会打架;都配成从机,没人给时钟,数据传不动。我曾经见过有人把 STM32 配成主机,WM8960 也配成主机,结果 SCK 上出现了两个驱动源,波形乱成一团。
采样率与位深计算:音频参数怎么算?
采样率和位深决定了音频质量,也直接决定了 SCK 的频率。公式其实很简单:
SCK 频率 = 采样率 × 位深 × 声道数 × 2
等一下,为什么乘以 2?因为 I2S 协议里,每个声道的有效数据位可能只占 16 位或 24 位,但 SCK 的周期数通常是位深的 2 倍。举个例子:
| 采样率 | 位深 | 声道数 | SCK 频率 |
|---|---|---|---|
| 44.1 kHz | 16 bit | 2(立体声) | 44.1k × 16 × 2 = 1.4112 MHz |
| 48 kHz | 16 bit | 2 | 48k × 16 × 2 = 1.536 MHz |
| 44.1 kHz | 24 bit | 2 | 44.1k × 24 × 2 = 2.1168 MHz |
| 48 kHz | 24 bit | 2 | 48k × 24 × 2 = 2.304 MHz |
这里有个坑:STM32 的 I2S 分频器不一定能精确生成所有频率。比如 44.1kHz 16bit 需要 1.4112 MHz,而 STM32 的时钟源通常是 8 MHz 或 72 MHz,分频后可能得到 1.411764 MHz,差了 0.04%。这点误差人耳基本听不出来,但如果你做专业音频设备,就得用外部晶振或者 PLL 精确锁定。
位深配置要点:
- STM32 的 I2S 外设支持 16 位、24 位、32 位数据长度
- WM8960 支持 16-24 位输入,内部处理精度是 24 位
- 如果 STM32 发 16 位数据,WM8960 会自动填充低位为 0
- 如果发 24 位数据,WM8960 会完整接收,音质更好但占用更多带宽
我个人建议:普通音乐播放用 16 位就够了,人耳对 16 位以上的动态范围提升感知有限。但如果你做录音或者高保真回放,可以考虑 24 位,WM8960 的 ADC/DAC 本来就是 24 位的,别浪费了硬件能力。
I2S 协议知识体系总览
下面这张图把 I2S 协议的核心知识点串起来了,你可以对照着看:
这张图把 I2S 协议的四个核心维度都列出来了。你调试的时候,按这个顺序排查:先看时序对不对,再看格式匹不匹配,然后确认主从配置,最后算采样率。大部分音频无声或噪声问题,都能在这四个环节里找到原因。