第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配置的完整流程,从时钟树到引脚分配,每一步都环环相扣。
2.5 生成代码前的最后检查
在点击Generate Code之前,我建议你做一次快速检查清单:
- 时钟树:PLLI2S使能了吗?I2S时钟频率是你预期的值吗?
- I2S参数:模式是Master吗?数据格式是I2S标准吗?位深是16位吗?采样率是48 kHz吗?
- 引脚:CK、SD、WS、MCK都分配了吗?有没有冲突?
- DMA:如果你打算用DMA传输(强烈建议),记得在DMA Settings里添加I2S的TX和RX通道。
我的习惯:每次生成代码前,我都会截一张Clock Configuration的图,再截一张Pinout的图。万一后面调试出问题,回头看一眼就知道配置有没有被改过。