4、时钟树与音频采样率:PLL配置计算,MCLK/LRCK/BCK关系推导

时钟,是音频系统的命脉。我见过不少开发者,I2S配置看起来全对,WM8960寄存器也写满了,但就是不出声——最后查出来,是MCLK和采样率没对上。说白了,时钟不对,音频数据就是一堆乱码。

这一章,我们就把时钟树彻底讲透。你搞懂了PLL怎么配、MCLK/LRCK/BCK之间什么关系,后面调音频就是水到渠成的事。

4.1 音频时钟的三个关键角色

先认识一下这三个家伙:

  • MCLK(主时钟):整个音频系统的基准时钟。WM8960内部的所有操作,包括ADC/DAC的调制器、数字滤波器,都依赖MCLK。通常频率是256×Fs或384×Fs。
  • BCK(位时钟):每个音频数据位对应一个BCK周期。I2S标准下,BCK频率 = 声道数 × 位深 × 采样率。比如双声道、16位、48kHz:BCK = 2 × 16 × 48000 = 1.536MHz。
  • LRCK(帧时钟):也叫字时钟,频率等于采样率。左声道数据在LRCK低电平传输,右声道在高电平传输。48kHz采样率,LRCK就是48kHz。

核心公式(请刻在脑子里):

BCK = 声道数 × 位深 × Fs

MCLK = BCK × 倍数(通常是4、8、16倍,取决于WM8960配置)

LRCK = Fs

举个例子:双声道、16位、48kHz采样,BCK = 2×16×48000 = 1.536MHz。如果WM8960配置为MCLK = 256×Fs,那MCLK = 256×48000 = 12.288MHz。你看,这三个时钟是严格绑定的。

4.2 STM32的时钟树与PLL配置

STM32的时钟树,说实话,刚接触时确实有点绕。但音频应用里,我们只需要关注一条路径:HSE → PLL → I2S时钟。

我个人习惯用外部8MHz晶振作为HSE。为什么?因为8MHz好分频,能精确得到各种音频采样率需要的MCLK。

STM32的I2S时钟源有两个选择:

  • PLLI2S:专用的I2S PLL,精度高,推荐使用。
  • 系统PLL(PLL):也可以分频给I2S,但灵活性差一些。

我们重点讲PLLI2S的配置。它的计算公式是:

PLLI2S输出频率 = HSE值 × PLLI2SM / (PLLI2SN × PLLI2SR)

其中:

  • PLLI2SM:预分频系数,通常固定为8(对应8MHz HSE)
  • PLLI2SN:倍频系数,范围192~432
  • PLLI2SR:输出分频系数,范围2~7

嗯,这里要注意:PLLI2SN和PLLI2SR的取值不是随便填的,必须保证输出频率在I2S外设的允许范围内(通常是1MHz~25MHz)。

4.3 常见采样率的MCLK计算

我们直接上实战。假设WM8960配置为MCLK = 256×Fs,HSE = 8MHz,双声道16位数据。

采样率 (Fs) MCLK (256×Fs) BCK (2×16×Fs) PLLI2SN PLLI2SR
8 kHz 2.048 MHz 256 kHz 256 5
16 kHz 4.096 MHz 512 kHz 256 5
44.1 kHz 11.2896 MHz 1.4112 MHz 271 3
48 kHz 12.288 MHz 1.536 MHz 384 5

避坑指南:44.1kHz的MCLK是11.2896MHz,这个频率用8MHz HSE很难精确得到。我曾在项目里直接用PLLI2SN=271、PLLI2SR=3,算出来是11.2896MHz吗?不是,是11.2896...MHz,误差在0.001%以内,人耳根本听不出来。但如果你用系统PLL去凑,误差可能到0.1%,那就能感觉到音调偏了。

4.4 WM8960的时钟配置

WM8960内部也有一个时钟分频器。它接收MCLK后,可以进一步分频得到内部需要的时钟。寄存器0x04(Clocking Register)控制这部分。

关键位:

  • BIT 6:4 (CLKSEL):选择MCLK来源,通常设为000(外部MCLK)
  • BIT 3:2 (SYSCLKDIV):系统时钟分频,00 = 不分频,01 = 2分频
  • BIT 1:0 (BCLKDIV):BCK分频,00 = 不分频,01 = 2分频

举个例子:如果MCLK = 12.288MHz,WM8960内部需要SYSCLK = 12.288MHz,那CLKSEL=000,SYSCLKDIV=00。BCK需要1.536MHz,而MCLK/BCK = 8,所以BCLKDIV也得配成对应的分频比。

我曾经踩过的坑:WM8960的BCLKDIV不是直接写分频系数,而是写一个索引值。比如MCLK/BCK=8时,BCLKDIV要写0x03(对应8分频)。如果你直接写8,WM8960会当成无效值,BCK就乱掉了。一定要看数据手册Table 42的映射表。

4.5 时钟树整体关系图

下面这张图,把整个时钟链路串起来了。你对照着看,思路会清晰很多。

STM32 I2S与WM8960时钟树关系图 STM32 I2S与WM8960时钟树关系图 HSE 8MHz PLLI2S I2S外设 MCLK WM8960 BCK / LRCK 关键说明: 1. HSE 8MHz 经 PLLI2S 倍频/分频后,输出精确的 MCLK 频率。 2. I2S 外设将 MCLK 分频得到 BCK 和 LRCK,通过 I2S 总线发送给 WM8960。 3. WM8960 内部再根据 MCLK 分频得到 SYSCLK 和内部 BCK。 4. 所有时钟必须严格同步,否则音频数据会错位或产生噪声。 5. 常见采样率对应的 MCLK 值:8kHz→2.048MHz, 16kHz→4.096MHz, 44.1kHz→11.2896MHz, 48kHz→12.288MHz。

4.6 代码实战:配置PLLI2S生成48kHz采样率

理论讲完了,我们直接上代码。下面这段是STM32CubeMX生成的HAL库代码,我加了详细注释。

/* 配置PLLI2S,生成48kHz采样率所需的12.288MHz MCLK */
void MX_I2S_ClockConfig(void)
{
    RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
    
    /* 选择PLLI2S作为I2S时钟源 */
    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2S;
    
    /* PLLI2S配置:HSE=8MHz, M=8, N=384, R=5 */
    /* 输出频率 = 8MHz × 384 / (8 × 5) = 12.288MHz */
    PeriphClkInitStruct.PLLI2S.PLLI2SM = 8;
    PeriphClkInitStruct.PLLI2S.PLLI2SN = 384;
    PeriphClkInitStruct.PLLI2S.PLLI2SR = 5;
    
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
    {
        Error_Handler();  /* 配置失败,检查参数 */
    }
}

个人经验:配置完PLLI2S后,最好读一下RCC寄存器确认输出频率。我习惯在调试串口打印PLLI2SR的值,确保它不是你手滑写错的。曾经有一次我把PLLI2SR写成6,结果MCLK变成10.24MHz,WM8960直接不工作,查了半天才发现。

4.7 I2S初始化中的时钟参数

PLLI2S配好了,I2S外设本身也要设置时钟分频。HAL库的hpi2s.Init结构体里,AudioFreq字段就是采样率。HAL库会根据这个值自动计算分频系数。

/* I2S初始化结构体 */
hi2s3.Instance = SPI3;  /* I2S3挂载在SPI3上 */
hi2s3.Init.Mode = I2S_MODE_MASTER_TX;  /* 主模式发送 */
hi2s3.Init.Standard = I2S_STANDARD_PHILIPS;  /* I2S Philips标准 */
hi2s3.Init.DataFormat = I2S_DATAFORMAT_16B;  /* 16位数据 */
hi2s3.Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE;  /* 使能MCLK输出 */
hi2s3.Init.AudioFreq = I2S_AUDIOFREQ_48K;  /* 48kHz采样率 */
hi2s3.Init.CPOL = I2S_CPOL_LOW;  /* 时钟极性 */
hi2s3.Init.ClockSource = I2S_CLOCK_PLL;  /* 使用PLLI2S */
hi2s3.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_ENABLE;  /* 全双工 */

if (HAL_I2S_Init(&hi2s3) != HAL_OK)
{
    Error_Handler();
}

这里有个细节:AudioFreq填的是采样率,但HAL库内部会把它转换成BCK频率,再根据MCLK输出使能情况计算分频比。如果你使能了MCLK输出,HAL库会自动保证MCLK = 256 × AudioFreq。

4.8 常见问题与调试方法

时钟配置出问题,音频系统基本就废了。我总结几个常见现象:

  • 无声:先量MCLK引脚有没有波形。没有?查PLLI2S配置。有但频率不对?查分频系数。
  • 声音变调:采样率不对。比如你配了48kHz,但实际MCLK是11.2896MHz(44.1kHz的),声音就会变慢变低。
  • 噪声/爆音:BCK和LRCK相位不对,或者MCLK抖动太大。检查I2S时序和电源滤波。

调试利器:用示波器同时抓MCLK、BCK、LRCK三根线。MCLK应该是BCK的整数倍(通常是4倍或8倍),LRCK应该是BCK的32倍(16位双声道)。如果比例不对,I2S配置肯定有问题。

时钟树这部分,说白了就是小学数学——乘除法算清楚,寄存器填对,就没问题。但恰恰是这种基础计算,最容易手滑。我建议你每次改采样率,都拿计算器按一遍MCLK和BCK,再和示波器实测值对比。养成习惯后,音频时钟这块就再也不会出幺蛾子了。