1. 课程导入
各位同学,欢迎来到这门实战课。我是你们的讲师,一个在嵌入式音频领域摸爬滚打了十几年的老工程师。今天咱们正式开始第一讲:项目概述与环境搭建。
说实话,我第一次接触WM8960这颗芯片时,也被它的功能吓了一跳。一颗小小的QFN封装芯片,集成了DAC、ADC、耳机功放、扬声器功放,甚至还支持数字麦克风接口。我当时就在想,这玩意儿要是能跟STM32配合好,那做USB声卡简直是降维打击。
1.1 WM8960芯片特性速览
WM8960是Cirrus Logic(原Wolfson)推出的一款低功耗立体声编解码器。我习惯把它称为“音频瑞士军刀”——功能太全了。
| 参数 | 数值 | 我的备注 |
|---|---|---|
| DAC信噪比 | 98dB | 够用,不是Hi-Fi级但不差 |
| ADC信噪比 | 94dB | 录音够清晰 |
| 采样率 | 8kHz ~ 96kHz | 覆盖语音到高保真音乐 |
| 耳机输出 | 40mW @ 16Ω | 推普通耳机没问题 |
| 扬声器输出 | 1W @ 8Ω | 接个小喇叭够响 |
| 接口 | I2S + I2C | I2S传音频数据,I2C配寄存器 |
核心要点:WM8960的I2S接口支持主从模式,我们这次用STM32做主设备,WM8960做从设备。时钟由STM32提供,WM8960只管收发数据。
为什么选这颗芯片?说白了,市面上能同时做USB声卡和音频网关的编解码器不多。WM8960内部有3D环绕、EQ均衡、自动电平控制(ALC),这些功能在音频网关场景下特别实用。我在做智能音箱项目时,就用它的ALC功能解决了远场拾音音量忽大忽小的问题。
1.2 USB声卡 vs 音频网关
这两个概念容易搞混,我当年也绕了一阵子。咱们用一张图说清楚。
USB声卡模式,说白了就是让电脑把STM32+WM8960识别成一个标准声卡。电脑放歌,数据走USB到STM32,STM32转成I2S信号送给WM8960,WM8960解码后从耳机口输出。反过来,麦克风采集的声音也能通过这个路径回传给电脑。
音频网关模式就不一样了。这时候STM32不再只是“数据搬运工”,它要参与音频处理。比如:把Line In进来的模拟信号数字化,跟USB音频流混音,再通过扬声器输出。我做过一个会议电话项目,就是这种架构——远程参会者的声音和本地发言人的声音要混合后一起播放。
我的经验:刚开始做音频网关时,我犯过一个低级错误——没处理好音频时钟同步。USB的帧时钟和I2S的位时钟不同步,结果声音断断续续。后来加了异步采样率转换(ASRC)才搞定。咱们后面会专门讲这个坑。
1.3 硬件平台介绍
咱们课程用的硬件平台,我挑了很久。最终选了STM32F407VGT6 + WM8960模块的组合。为什么是F407?因为它有USB OTG FS,有I2S外设,主频168MHz做音频处理绰绰有余。
| 硬件模块 | 型号/规格 | 作用 |
|---|---|---|
| 主控MCU | STM32F407VGT6 | USB通信、I2S控制、音频数据处理 |
| 音频编解码 | WM8960 | ADC/DAC、耳机功放、扬声器功放 |
| USB接口 | USB OTG FS | 连接PC,实现USB Audio Class |
| 音频输入 | 3.5mm Line In + 板载麦克风 | 模拟音频采集 |
| 音频输出 | 3.5mm耳机口 + 扬声器接口 | 模拟音频播放 |
| 调试接口 | SWD + UART | 程序下载与日志输出 |
硬件连接上,我画了个简图,大家先有个印象:
注意:WM8960的I2C地址是0x1A(7位地址)。如果你用的是其他模块,记得确认地址。我曾经买过一个山寨模块,地址被改成了0x1B,查了半天才发现。
1.4 开发环境搭建
环境搭建这块,我尽量说得简洁。咱们用两件套:STM32CubeMX生成初始化代码,MDK-ARM(Keil)写业务逻辑。
1.4.1 STM32CubeMX配置要点
打开CubeMX,选STM32F407VGT6。我习惯按这个顺序配:
- RCC配置:HSE外部晶振,主频168MHz
- USB OTG FS:使能Device模式,选USB Audio Class
- I2S3:配置为主机模式,标准飞利浦格式,16位数据
- I2C1:标准模式100kHz,用于控制WM8960
- GPIO:WM8960的复位引脚、MCLK时钟输出
关键参数:I2S的采样率我设为48kHz。为什么?因为USB Audio Class 1.0标准强制支持48kHz,而且48kHz是绝大多数音频内容的原生采样率。你设成44.1kHz也行,但PC端可能会做SRC(采样率转换),音质反而下降。
1.4.2 MDK工程配置
CubeMX生成代码后,用MDK打开。我个人习惯做这几件事:
- 把优化等级设为-O2,音频处理对性能有要求
- 开启微库(MicroLIB),减少printf等函数的代码体积
- 添加USB Audio Class中间件(CubeMX已经帮我们生成了)
- 把WM8960的驱动文件(.c/.h)加到工程里
/* 工程文件结构示意 */
Project/
├── Core/
│ ├── Src/
│ │ ├── main.c
│ │ ├── usb_audio.c /* USB音频处理 */
│ │ └── wm8960.c /* WM8960驱动 */
│ └── Inc/
│ ├── main.h
│ ├── usb_audio.h
│ └── wm8960.h
├── Drivers/
│ ├── STM32F4xx_HAL_Driver/
│ └── BSP/
└── MDK-ARM/
└── project.uvprojx
避坑指南:我曾经在MDK里忘了勾选“Use MicroLIB”,结果USB Audio的缓冲区申请失败,声卡死活不工作。折腾了两天才发现是堆太小。建议把堆大小设到0x1000以上。
1.5 第一个测试:让WM8960出声
环境搭好后,咱们先做个最简单的测试——让WM8960播放一个1kHz正弦波。这步能验证I2C通信和I2S数据传输是否正常。
/* WM8960初始化代码片段 */
void WM8960_Init(void)
{
/* 复位WM8960 */
WM8960_WriteReg(0x0F, 0x0000); // 软件复位
HAL_Delay(10);
/* 配置基本参数 */
WM8960_WriteReg(0x19, 0x0017); // 使能左声道DAC
WM8960_WriteReg(0x1A, 0x0017); // 使能右声道DAC
WM8960_WriteReg(0x02, 0x0133); // 左声道音量
WM8960_WriteReg(0x03, 0x0133); // 右声道音量
/* 使能耳机输出 */
WM8960_WriteReg(0x31, 0x00FF); // 耳机音量最大
WM8960_WriteReg(0x34, 0x0003); // 使能耳机输出
}
这段代码写完后,用DMA往I2S发送一个正弦波表。如果听到“嘟——”的声音,恭喜你,硬件和环境都没问题。
我记得第一次调通时,听到耳机里传来正弦波的声音,那种成就感比中了彩票还爽。虽然只是个简单的测试,但意味着从USB到I2S到WM8960的整条链路都通了。
1.6 本章小结
这一章咱们把项目轮廓理清了。WM8960是什么、USB声卡和音频网关有什么区别、硬件怎么连、环境怎么搭。这些东西是后面所有章节的基础。