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/噪声门) |
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 | – | 保留 |
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 的寄存器访问流程:
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 配置 |
4.5 寄存器配置的常见陷阱
嗯,这里我要多说几句。寄存器映射看着简单,但实际项目中容易掉坑。我总结了几条:
- 写寄存器必须完整写 9 位: 即使高 1 位是保留位,也要补 0。否则 WM8960 可能不认。
- 电源管理寄存器有依赖关系: 比如开启 ADC 前,必须先开 VREF 和 VMID。顺序错了,ADC 读出来全是 0。
- 音量寄存器有更新标志: D8 位必须置 1,音量值才会生效。我刚开始忘了置位,调了半天音量没变化。
- 时钟寄存器跟采样率绑定: 如果 MCLK 是 12.288 MHz,采样率 48 kHz 时 SR 位要配成 000。配错了,声音会变调。