第2章:STM32CubeMX配置I2S外设:时钟树、参数与引脚

好,咱们正式开始动手配置。上一章我们聊了WM8960和I2S的基本概念,这一章就进入实操环节——用STM32CubeMX把I2S外设的硬件环境搭起来。

我个人习惯是先把时钟树理清楚,再配置外设参数,最后分配引脚。这个顺序能避免很多回头改配置的麻烦。你想想看,时钟源没选对,后面采样率算出来也是错的,对吧?

2.1 时钟树配置——I2S的“心跳”

I2S的时钟源,说白了就是决定采样率准不准的关键。STM32的I2S时钟可以从PLLI2S、系统时钟(SYSCLK)或者外部时钟引脚引入。我一般用PLLI2S,因为它可以独立配置,不影响主系统时钟。

核心原则:I2S的位时钟(BCLK)必须精确等于 采样率 × 声道数 × 位深。比如48kHz采样、立体声、16位数据,BCLK就是 48000 × 2 × 16 = 1.536 MHz。

在CubeMX的Clock Configuration页面里,你需要找到PLLI2S的配置项。以STM32F407为例,我通常这样设置:

  • HSE:8 MHz外部晶振(开发板常见值)
  • PLL_M:8(分频,使VCO输入为1 MHz)
  • PLL_N:192(倍频,VCO输出192 MHz)
  • PLL_P:2(主系统时钟分频,得到96 MHz)
  • PLLI2S_N:192(I2S专用倍频)
  • PLLI2S_R:4(I2S分频,得到48 MHz)

这样I2S模块得到的时钟是48 MHz。为什么选这个值?因为后面配置采样率时,48 MHz可以整除很多常见采样率,误差小。

小技巧:如果你用的外部晶振不是8 MHz,记得调整PLL_M的值,保证VCO输入在1-2 MHz范围内。我曾经在项目里用25 MHz晶振,忘了改PLL_M,结果I2S时钟偏了,录音音调都变了——排查了半天才发现。

2.2 I2S参数配置——主从模式、数据格式、采样率

时钟搞定后,切换到Pinout & Configuration页面,找到I2S外设。STM32的I2S其实是挂在SPI接口上的,所以你要在SPI的配置里选择I2S模式。

2.2.1 主从模式选择

WM8960既可以做主设备也可以做从设备。我习惯让STM32做主设备,WM8960做从设备。这样时钟由STM32产生,时序控制更直接。

模式 时钟源 适用场景
主模式(Master) STM32内部生成BCLK和WS 单板录音/播放,WM8960作为从设备
从模式(Slave) 外部提供BCLK和WS 多板同步,或WM8960做主设备

在CubeMX里,I2S Mode选择Master Transmit / Master Receive。注意,如果你要同时收发,选Full-Duplex Master。

2.2.2 数据格式与位深

WM8960支持多种数据格式,但最常用的是I2S标准格式(Philips格式)。数据在WS变化后的第二个时钟沿开始传输。

位深方面,我建议选16位。为什么?因为16位数据在STM32的DMA传输中效率最高,而且WM8960内部DAC/ADC也是16位精度。你用24位或32位,实际有效精度并不会提升,反而增加带宽压力。

注意:如果你选了16位数据格式,但WM8960配置成24位模式,数据会错位。我遇到过一位学员,录音全是噪声,最后发现是CubeMX里配了16位,WM8960寄存器配了24位——两边没对齐。

2.2.3 采样率设置

采样率是音频项目的核心参数。常见的采样率有:8 kHz(语音)、16 kHz(宽带语音)、44.1 kHz(CD音质)、48 kHz(专业音频)。

在CubeMX里,I2S的采样率是通过时钟分频器算出来的。公式是:

采样率 = I2S时钟频率 / (分频系数 × 声道数 × 位深 × 2)

其中分频系数由I2S_Prescaler和I2S_MCK_Output决定。我一般这样算:

  • 目标采样率:48 kHz
  • 声道数:2(立体声)
  • 位深:16
  • 所需BCLK:48k × 2 × 16 = 1.536 MHz
  • I2S时钟:48 MHz
  • 分频系数:48 MHz / 1.536 MHz = 31.25 → 取整32(实际用32分频)

在CubeMX的Parameter Settings里,把Audio Frequency设为48 kHz,软件会自动计算分频值。你也可以手动输入I2S_Prescaler为8(因为内部还有额外分频)。

实际经验:48 kHz采样率下,16位立体声的数据率是 48k × 2 × 16 = 1.536 Mbps。这个速率用SPI DMA完全扛得住,CPU占用率几乎为0。

2.3 引脚分配——别让硬件坑了你

引脚分配看起来简单,但最容易出问题。I2S需要以下引脚:

信号 功能 STM32引脚(以F407为例)
CK 位时钟(BCLK) PB13 / SPI2_SCK
SD 数据线(双向) PB15 / SPI2_MOSI
WS 帧同步(左右声道选择) PB12 / SPI2_NSS
MCK 主时钟(可选) PC6 / I2S2_MCK

在CubeMX里,你只需要在I2S配置中使能对应的引脚,软件会自动分配。但我建议你手动检查一下:

  • MCK引脚:WM8960需要主时钟(MCLK)才能工作。如果你用的是STM32F4,记得在I2S配置里勾选Master Clock Output Enable,然后分配MCK引脚。
  • 引脚冲突:I2S引脚可能和其他外设共用。比如SPI2的引脚也可能被USART或定时器占用。在CubeMX的Pinout视图里,冲突的引脚会变红。

避坑指南:我曾经在一个项目里,I2S的CK引脚和SD引脚在PCB上画反了。结果数据一直收不到,用逻辑分析仪一看,时钟和数据颠倒了。所以分配完引脚后,一定要对照原理图再确认一遍。

2.4 整体配置流程——一张图说清楚

下面这张SVG图总结了I2S配置的完整流程,从时钟树到引脚分配,每一步都环环相扣。

I2S配置流程图 I2S外设配置流程 1. 时钟树配置 2. I2S参数设置 3. 引脚分配 4. 生成代码 说明: 每一步都依赖上一步的正确配置。时钟树错了,采样率就不准;参数错了,数据格式就不对;引脚错了,硬件就不通。

2.5 生成代码前的最后检查

在点击Generate Code之前,我建议你做一次快速检查清单:

  1. 时钟树:PLLI2S使能了吗?I2S时钟频率是你预期的值吗?
  2. I2S参数:模式是Master吗?数据格式是I2S标准吗?位深是16位吗?采样率是48 kHz吗?
  3. 引脚:CK、SD、WS、MCK都分配了吗?有没有冲突?
  4. DMA:如果你打算用DMA传输(强烈建议),记得在DMA Settings里添加I2S的TX和RX通道。

我的习惯:每次生成代码前,我都会截一张Clock Configuration的图,再截一张Pinout的图。万一后面调试出问题,回头看一眼就知道配置有没有被改过。