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 系统架构概览

在动手搭工程之前,咱们先看看整个系统的数据是怎么跑的。我画了一张图,帮你理清脉络。

系统数据流与硬件连接框架 麦克风输入 WM8960 ADC / DAC I2S 从机 STM32F4 I2S 主机 DMA 双缓冲 耳机 I2C 控制(配置寄存器) MCLK / BCLK / LRCLK 关键说明: 1. STM32 作为 I2S 主机,提供 BCLK 和 LRCLK,WM8960 作为从机。 2. 录音数据通过 I2S 的 SDI 引脚进入 STM32,放音数据通过 SDO 引脚送出。 3. 控制接口使用 I2C,用于配置 WM8960 的采样率、增益、路由等。 4. 时钟必须同步,否则会出现“噼啪”爆音。

你看,整个系统其实不复杂。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中:

  1. 找到Connectivity → SPI2(F407的I2S2挂在这个SPI上)
  2. Mode选择:I2S2 Full-Duplex Master
  3. 配置参数:
    • 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、调试接口都配齐了