4. PCM帧结构
PCM(Pulse Code Modulation)接口是音频Codec与主控(CPU/DSP)之间最常用的数字音频传输总线。理解PCM帧结构是调试音频驱动的基石,任何位时钟偏移、帧同步错位或数据格式不匹配,都会导致无声、杂音或通道错乱。本节从物理信号到数据格式,逐层拆解PCM帧的完整结构。
4.1 PCM接口的三大信号线
一个标准的PCM总线由三根核心信号线组成,外加一根可选的MCLK(主时钟):
| 信号名称 | 缩写 | 方向(Codec侧) | 功能描述 |
|---|---|---|---|
| 位时钟 | BCLK / BITCLK | 输入或输出 | 每个脉冲对应一个数据位,决定串行传输速率 |
| 帧同步 | FSYNC / LRCLK / WS | 输入或输出 | 标识一个音频帧的开始,同时指示左/右声道 |
| 数据线 | DIN / DOUT / SDATA | 输入或输出 | 串行传输音频采样数据,通常为二进制补码格式 |
| 主时钟(可选) | MCLK / MASTER CLK | 输入 | 为Codec内部Δ-Σ调制器提供基准时钟,频率通常为BCLK的整数倍 |
4.2 帧同步信号与位时钟的时序关系
帧同步信号(FSYNC)的频率等于音频采样率(Fs),即每秒钟的帧数等于采样率。位时钟(BCLK)的频率则取决于采样率、位宽和通道数:
BCLK = Fs × 通道数 × 位宽
例如:采样率 48kHz,立体声(2通道),16位宽:
BCLK = 48000 × 2 × 16 = 1.536 MHz
帧同步的占空比在不同模式下有差异:
- 标准I²S模式: FSYNC为50%占空比的方波,高电平表示左声道,低电平表示右声道(或相反,取决于Codec配置)。
- 左对齐/右对齐模式: FSYNC通常为短脉冲(一个BCLK周期宽度),在脉冲后立即开始传输数据。
- DSP模式: FSYNC为短脉冲,且数据在FSYNC有效后延迟1个BCLK周期开始传输。
4.3 三种主流帧格式详解
PCM接口的帧格式定义了数据位与帧同步信号的对齐方式。主流格式包括左对齐(Left Justified)、右对齐(Right Justified)和DSP模式(DSP Mode / PCM Mode)。
4.3.1 左对齐(Left Justified)
左对齐格式中,数据字的最高位(MSB)在帧同步信号有效后的第一个BCLK周期立即开始传输。数据位紧贴帧同步边沿,没有延迟位。左对齐常用于早期DAC/ADC,兼容性较好。
- 特点: MSB与FSYNC边沿对齐,无延迟位。
- 适用场景: 部分老式Codec、飞利浦标准I²S的变体。
- 驱动配置: 通常需要设置
SND_SOC_DAIFMT_LEFT_J。
4.3.2 右对齐(Right Justified)
右对齐格式中,数据字的最低位(LSB)在帧同步信号结束前的最后一个BCLK周期对齐。这意味着数据字的MSB可能不在帧开始处,而是根据位宽填充前导零。右对齐在早期日本厂商的Codec中较为常见。
- 特点: LSB与FSYNC结束边沿对齐,高位补零。
- 适用场景: 部分AKM、NJR系列Codec。
- 驱动配置: 通常需要设置
SND_SOC_DAIFMT_RIGHT_J。
4.3.3 DSP模式(DSP Mode / PCM Mode)
DSP模式是一种时分复用(TDM)变体,帧同步信号为短脉冲,数据在FSYNC有效后延迟1个BCLK周期开始传输。左声道和右声道的数据连续传输,中间无间隙。DSP模式在蓝牙音频、数字无线麦克风和部分DSP Codec中广泛使用。
- 特点: FSYNC为短脉冲,数据延迟1 BCLK,左右声道连续传输。
- 适用场景: 蓝牙A2DP、Qualcomm WCD系列、TI TLV320系列。
- 驱动配置: 通常需要设置
SND_SOC_DAIFMT_DSP_A(延迟1 BCLK)或SND_SOC_DAIFMT_DSP_B(无延迟)。
4.4 帧格式对比表
| 格式 | FSYNC类型 | MSB对齐位置 | LSB对齐位置 | 延迟位 | 典型应用 |
|---|---|---|---|---|---|
| 左对齐 | 短脉冲或50%占空比 | FSYNC有效边沿 | 帧内固定位置 | 0 | 老式DAC、飞利浦标准 |
| 右对齐 | 短脉冲 | 帧内高位补零 | FSYNC结束边沿 | 0 | AKM、NJR Codec |
| DSP模式(A/B) | 短脉冲 | FSYNC后1 BCLK(A)或0 BCLK(B) | 帧结束前 | 0或1 | 蓝牙、DSP Codec、TDM |
4.5 PCM帧结构SVG示意图
下图展示了标准I²S(左对齐变体)与DSP模式在一个完整帧内的数据排列差异。图中以16位立体声为例,BCLK频率为1.536 MHz,Fs = 48 kHz。
4.6 驱动中帧格式配置实战
在Linux ALSA驱动中,帧格式通过 snd_soc_dai_set_fmt() 接口配置。以下是一个典型的立体声PCM接口初始化代码片段:
/* 配置DAI格式:DSP模式,延迟1 BCLK,BCLK下降沿采样,FSYNC高电平有效 */
int ret = snd_soc_dai_set_fmt(codec_dai,
SND_SOC_DAIFMT_DSP_A |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS);
if (ret < 0) {
dev_err(dev, "Failed to set DAI format: %d\n", ret);
return ret;
}
/* 配置数据宽度为16位 */
ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 2, 16);
if (ret < 0) {
dev_err(dev, "Failed to set TDM slot: %d\n", ret);
return ret;
}
/* 配置系统时钟 */
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 12288000, SND_SOC_CLOCK_IN);
if (ret < 0) {
dev_err(dev, "Failed to set sysclk: %d\n", ret);
return ret;
}
SND_SOC_DAIFMT_DSP_A:DSP模式,数据延迟1 BCLK。SND_SOC_DAIFMT_NB_NF:正常BCLK极性(上升沿采样),正常FSYNC极性(高电平有效)。SND_SOC_DAIFMT_CBS_CFS:Codec作为BCLK和FSYNC的从设备(由主控提供时钟)。snd_soc_dai_set_tdm_slot():配置TDM时隙掩码为0x3(启用slot 0和1),每个slot宽度为16位。
4.7 调试检查清单
当PCM接口出现无声或杂音时,按以下顺序排查帧结构相关项:
- BCLK频率计算: 使用示波器或逻辑分析仪测量BCLK频率,确认与
Fs × 通道数 × 位宽一致。 - FSYNC极性: 确认FSYNC高电平对应左声道还是右声道,与Codec数据手册一致。
- 数据对齐: 抓取FSYNC与数据线的相对位置,确认MSB是否在预期位置开始传输。
- 延迟位检查: 对于DSP模式,确认数据是否延迟了1个BCLK周期。
- 位宽匹配: 确认主控发送的位宽与Codec配置的位宽一致,避免高位截断或低位补零错误。