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声卡 vs 音频网关 架构对比 USB声卡模式 PC/USB Host → STM32 → WM8960 音频数据流:USB IN/OUT 音频网关模式 音频输入 → STM32处理 → 音频输出 数据流:I2S双向 + 内部DSP处理 可切换 两种模式的核心区别 • USB声卡:PC通过USB控制WM8960,STM32做USB-I2S桥接 • 音频网关:音频信号在STM32内部路由、混音、处理后再输出 • 我们的课程:两种模式都做,并且支持动态切换

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 程序下载与日志输出

硬件连接上,我画了个简图,大家先有个印象:

硬件连接框图 STM32F407 I2S主设备 WM8960 I2S从设备 I2S (SCK/WS/SD) I2C (SCL/SDA) 控制 USB OTG FS USB音频流 耳机/扬声器 模拟音频

注意:WM8960的I2C地址是0x1A(7位地址)。如果你用的是其他模块,记得确认地址。我曾经买过一个山寨模块,地址被改成了0x1B,查了半天才发现。

1.4 开发环境搭建

环境搭建这块,我尽量说得简洁。咱们用两件套:STM32CubeMX生成初始化代码,MDK-ARM(Keil)写业务逻辑。

1.4.1 STM32CubeMX配置要点

打开CubeMX,选STM32F407VGT6。我习惯按这个顺序配:

  1. RCC配置:HSE外部晶振,主频168MHz
  2. USB OTG FS:使能Device模式,选USB Audio Class
  3. I2S3:配置为主机模式,标准飞利浦格式,16位数据
  4. I2C1:标准模式100kHz,用于控制WM8960
  5. 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声卡和音频网关有什么区别、硬件怎么连、环境怎么搭。这些东西是后面所有章节的基础。