1. 项目概述与环境搭建
各位同学,欢迎来到这个实战课程。我是你们的讲师,一个在嵌入式音频领域摸爬滚打多年的老工程师。今天咱们正式开始第一讲:了解WM8960这颗芯片,再把开发环境搭起来。
说实话,音频项目在嵌入式里算是个“硬骨头”。它不像点个LED、读个按键那么简单。它涉及时钟同步、数据流实时处理、编解码配置……稍不留神,出来的声音就是“嘶嘶”的噪音。我自己刚入行那会儿,就被I2S的时钟极性折腾过一整个通宵。
但别怕。咱们一步一步来。先把基础打牢。
1.1 WM8960音频编解码器特性速览
WM8960是Cirrus Logic(原Wolfson)推出的一款低功耗立体声编解码器。为什么选它?说白了,这颗芯片在便携式音频设备里太常见了。我经手的几个量产项目,从智能音箱到录音笔,用的都是它。
它的核心特性,我整理了一张表,你一看就明白:
| 特性 | 参数/说明 |
|---|---|
| 音频分辨率 | 16/20/24/32 bit |
| 采样率范围 | 8 kHz ~ 96 kHz |
| 信噪比(SNR) | DAC: 98 dB, ADC: 97 dB |
| 音频接口 | I2S / 左对齐 / DSP模式 |
| 控制接口 | I2C(从机地址 0x1A 或 0x1B) |
| 内置功能 | 麦克风偏置、耳机驱动、扬声器驱动(1W/通道) |
| 工作电压 | 核心 2.7V~3.6V,数字 I/O 1.65V~3.6V |
嗯,这里有个重点。WM8960支持全双工。什么意思?就是它可以同时录音和放音。这在很多场景下是刚需——比如对讲机、实时语音传输。咱们这个项目,就是要把它这个能力发挥出来。
项目核心链路:
麦克风 → WM8960 ADC → I2S(录音数据)→ STM32 → I2S(播放数据)→ WM8960 DAC → 耳机/喇叭
全程全双工,数据流不中断。
1.2 系统架构概览
在动手搭工程之前,咱们先看看整个系统的数据是怎么跑的。我画了一张图,帮你理清脉络。
你看,整个系统其实不复杂。STM32是大脑,负责控制和处理数据。WM8960是声卡,负责模拟和数字之间的转换。I2S是高速公路,负责把数字音频数据搬来搬去。I2C是控制总线,负责给WM8960下指令。
1.3 搭建STM32CubeMX工程
好,理论说完了,咱们开始动手。我个人习惯用STM32CubeMX生成初始化代码,省时省力,不容易漏配置。
咱们以STM32F407VET6为例(其他型号思路一样)。打开CubeMX,新建工程,选择芯片型号。
1.3.1 配置系统时钟
音频对时钟要求很高。WM8960需要MCLK(主时钟),通常是采样率的256倍或384倍。比如采样率48kHz,MCLK就是12.288 MHz。这个频率必须精准,否则声音会变调。
我建议这样配:
- 外部晶振:8 MHz(HSE)
- 主频:168 MHz(HCLK)
- APB1时钟:42 MHz(I2S外设挂在这条总线上)
- I2S时钟源:使用PLLI2S,专门生成音频时钟
我的经验:千万别偷懒用内部RC振荡器做I2S时钟。内部RC精度不够,出来的音频会有可闻的频偏。我吃过这个亏,产品送到客户那里被投诉“音调不准”,后来全部换成外部晶振才解决。
在CubeMX的Clock Configuration页面,配置如下:
HSE = 8 MHz
PLL_M = 8, PLL_N = 336, PLL_P = 2 → 主频 168 MHz
PLLI2S_N = 258, PLLI2S_R = 3 → 生成 12.288 MHz MCLK
1.3.2 配置调试接口
调试接口必须配,不然程序烧进去跑没跑你都不知道。我一般选Serial Wire(SWD),只用两根线(SWDIO + SWCLK),省引脚。
- 在Pinout & Configuration页面,找到System Core → SYS
- Debug选项选择:Serial Wire
警告:如果选了JTAG,会占用PB3、PB4、PA15等引脚。这些引脚可能和你的I2S或I2C冲突。我建议一律用SWD,除非你非要接JTAG调试器。
1.3.3 配置I2S外设
接下来配置I2S。咱们用的是全双工模式,所以需要同时使能I2S的发送和接收。
在CubeMX中:
- 找到Connectivity → SPI2(F407的I2S2挂在这个SPI上)
- Mode选择:I2S2 Full-Duplex Master
- 配置参数:
- Frame Format: Philips Standard(最常用)
- Data Width: 16 bits
- Audio Sampling Frequency: 48 kHz
- Clock Polarity: Low(这个要看WM8960的配置,我习惯用Low)
- Master Clock Output: Enable(输出MCLK给WM8960)
配好之后,CubeMX会自动计算分频系数。你可以在Parameter Settings里看到计算结果。如果算出来不是整数,说明时钟树没配好,回去调整PLLI2S的参数。
1.3.4 配置I2C控制接口
WM8960的寄存器是通过I2C配置的。咱们用I2C1,速度选400 kHz(快速模式)。
- Connectivity → I2C1
- Mode: I2C
- Timing: 根据你的HCLK自动计算,确保SCL频率接近400 kHz
引脚分配,我建议这样:
| 信号 | 引脚 | 备注 |
|---|---|---|
| I2S2_CK (BCLK) | PB13 | 位时钟 |
| I2S2_SD (SDO) | PB15 | 播放数据输出 |
| I2S2_ext_SD (SDI) | PC3 | 录音数据输入 |
| I2S2_WS (LRCLK) | PB12 | 帧时钟 |
| I2S2_MCK (MCLK) | PC6 | 主时钟输出 |
| I2C1_SCL | PB6 | I2C时钟 |
| I2C1_SDA | PB7 | I2C数据 |
1.4 生成代码与验证
所有配置完成后,点击Project → Generate Code。记得在Project Settings里选好IDE(我用的是MDK-ARM,你习惯用哪个都行)。
生成后,打开工程。先别急着写业务逻辑。咱们先验证一下时钟对不对。
在main.c里,加一段测试代码,用示波器或者逻辑分析仪看MCLK引脚(PC6)的输出:
// 在 main() 中,HAL_Init() 和 SystemClock_Config() 之后
// 使能 I2S 时钟输出
HAL_I2S_MspInit(&hi2s2); // 确保底层初始化完成
// 然后测量 PC6 引脚频率
// 应该输出 12.288 MHz 的方波
验证要点:
- MCLK频率:12.288 MHz ± 0.1%
- BCLK频率:48 kHz × 16 bit × 2通道 = 1.536 MHz
- LRCLK频率:48 kHz(与采样率一致)
如果频率偏差超过0.5%,音频就会明显变调。务必调整时钟树直到精准。
1.5 本章小结
好了,第一讲的内容就到这里。咱们做了三件事:
- 了解了WM8960这颗芯片的脾气——它是个全双工的好手
- 画出了系统的数据流框架——心里有张图,干活不慌
- 搭好了CubeMX工程——时钟、I2S、I2C、调试接口都配齐了