4. WM8960 寄存器映射:0x00–0x3F 的控制位与功能

WM8960 的寄存器空间其实不大,总共就 64 个(0x00–0x3F)。但你别小看这 64 个地址,它们管着音频通路、音量、时钟、电源、DSP 模式……几乎所有的功能。我第一次看数据手册时,面对满篇的位定义也有点头大。后来我习惯把寄存器按功能分组,再配合 I2C 调试,慢慢就摸清了门道。

这一章,我就带你把这 64 个寄存器拆开揉碎,讲清楚每个地址对应的功能,以及哪些位是咱们做 STM32 驱动时必须关注的。

4.1 寄存器地址空间概览

WM8960 的寄存器地址是 7 位宽,但实际只用到 0x00–0x3F。每个寄存器 9 位数据(D8–D0),通过 I2C 传输时拆成两个字节:高字节(0–1 位有效)和低字节(8 位)。

我个人习惯把寄存器分成这几类:

地址范围 功能组 典型寄存器
0x00–0x01 软件复位与ID R0 (软件复位), R1 (版本ID)
0x02–0x0F 电源管理与时钟 R2 (电源1), R3 (电源2), R4–R7 (时钟/采样率)
0x10–0x1F 音频接口与通路 R10 (接口格式), R12–R15 (左右DAC/ADC通路)
0x20–0x2F 音量控制 R20–R23 (DAC/ADC 数字音量), R24–R27 (模拟增益)
0x30–0x3F DSP/3D/限幅器 R32 (3D), R33 (限幅器), R34–R39 (ALC/噪声门)
小技巧: 调试时我习惯先读 R1(0x01),如果返回 0x0043,说明 I2C 通信正常。这是最快速的“心跳检测”。

4.2 关键寄存器逐位解析

下面我挑几个最常用的寄存器,结合我在项目中的踩坑经验,给你讲清楚每个控制位的实际作用。

4.2.1 R0 (0x00) – 软件复位

这个寄存器写 0x0000 就能复位整个芯片。注意:复位后所有寄存器恢复默认值,包括电源管理位。我曾经在初始化序列里忘了先复位,结果之前调试时改乱的寄存器状态一直残留,折腾了半天才发现。

4.2.2 R2 (0x02) – 电源管理 1

这个寄存器控制着核心模块的供电,位定义如下:

位 名称 功能
D8 VMIDSEL VMID 偏置选择(00=关, 01=75kΩ, 10=500kΩ, 11=5kΩ)
D7 VREF 参考电压使能(1=开启)
D6 AINL 左声道模拟输入偏置
D5 AINR 右声道模拟输入偏置
D4 ADCL 左声道 ADC 使能
D3 ADCR 右声道 ADC 使能
D2 MICB 麦克风偏置使能
D1 DIGENB 数字核心使能(必须置1)
D0 – 保留
注意: D1 (DIGENB) 必须置 1,否则数字核心不工作。我见过有人只配了模拟电源,忘了开数字核心,结果 I2C 能读写但没声音输出。

4.2.3 R10 (0x0A) – 音频接口格式

这个寄存器决定了 WM8960 跟 STM32 的 I2S 怎么握手。位定义如下:

  • D8–D6 (FORMAT): 选择音频协议。我个人只用 000(I2S 标准格式)或 010(左对齐)。
  • D5 (WL): 字长选择。0=16位,1=20位,2=24位,3=32位。STM32 的 I2S 外设通常配 16 位或 24 位。
  • D4 (LRP): 左右声道极性。默认 0 是左声道低电平,右声道高电平。如果接反了,左右声道会互换。
  • D3–D0: 保留或用于其他格式配置。

避坑指南: 我曾经把 WL 配成 20 位,但 STM32 的 I2S 只支持 16/24/32 位。结果数据错位,声音全是噪声。后来我统一用 16 位,两边都省心。

4.2.4 R20–R23 – 数字音量控制

这四个寄存器控制 DAC 和 ADC 的数字音量,范围 0–255(对应静音到最大增益)。注意:

  • R20: 左 DAC 数字音量
  • R21: 右 DAC 数字音量
  • R22: 左 ADC 数字音量
  • R23: 右 ADC 数字音量

每个寄存器的 D8 位是更新标志(必须置 1 才能写入音量值)。我习惯先写音量值,再写 D8=1 触发更新。

4.3 寄存器映射与 I2C 地址的关系

WM8960 的 I2C 设备地址是 0x1A(7 位地址)。写寄存器时,I2C 发送:设备地址 + 寄存器地址 + 数据高字节 + 数据低字节。读寄存器时,需要先写寄存器地址,再重新开始读取。

下面这张 SVG 图展示了从 STM32 到 WM8960 的寄存器访问流程:

WM8960 寄存器访问流程 STM32 I2C 访问 WM8960 寄存器流程 STM32 主控 I2C 总线 WM8960 从机 寄存器地址 控制位解析 说明: 1. STM32 通过 I2C 发送设备地址 0x1A 2. 随后发送寄存器地址(如 0x02) 3. 再发送 9 位数据(拆成两个字节) 4. WM8960 解析控制位并执行对应功能

4.4 常用寄存器速查表

为了方便你写驱动时快速查阅,我把最常用的几个寄存器整理成了一张表。你可以把它打印出来贴在工位上。

地址 名称 默认值 主要功能
0x00 R0 0x0000 软件复位
0x01 R1 0x0043 版本 ID(读回 0x0043 表示正常)
0x02 R2 0x0000 电源管理 1(VMID、VREF、ADC、MICB)
0x03 R3 0x0000 电源管理 2(DAC、输出级、LOUT/ROUT)
0x04 R4 0x0050 时钟管理 1(采样率、MCLK 分频)
0x05 R5 0x0000 时钟管理 2(PLL 配置)
0x0A R10 0x0000 音频接口格式(I2S、左对齐、字长)
0x14 R20 0x00FF 左 DAC 数字音量(0=静音, 255=最大)
0x15 R21 0x00FF 右 DAC 数字音量
0x16 R22 0x00FF 左 ADC 数字音量
0x17 R23 0x00FF 右 ADC 数字音量
0x20 R32 0x0000 3D 环绕效果使能
0x21 R33 0x0000 限幅器/ALC 配置
我的习惯: 写驱动前,我会先把上表里的寄存器默认值读一遍,确认芯片复位正常。如果读回来的值跟手册对不上,先查 I2C 时序,再查电源。

4.5 寄存器配置的常见陷阱

嗯,这里我要多说几句。寄存器映射看着简单,但实际项目中容易掉坑。我总结了几条:

  • 写寄存器必须完整写 9 位: 即使高 1 位是保留位,也要补 0。否则 WM8960 可能不认。
  • 电源管理寄存器有依赖关系: 比如开启 ADC 前,必须先开 VREF 和 VMID。顺序错了,ADC 读出来全是 0。
  • 音量寄存器有更新标志: D8 位必须置 1,音量值才会生效。我刚开始忘了置位,调了半天音量没变化。
  • 时钟寄存器跟采样率绑定: 如果 MCLK 是 12.288 MHz,采样率 48 kHz 时 SR 位要配成 000。配错了,声音会变调。
曾经有一次: 我在调试录音功能时,ADC 始终没数据。查了两天,最后发现是 R2 的 ADCL 位没置 1。嗯,这种低级错误,犯过一次就再也不会忘了。

4.6 小结