3. WM8960寄存器配置入门:I2C控制接口初始化,核心寄存器配置流程
好,这一章我们正式开始跟WM8960“对话”。
WM8960这颗芯片,说白了就是个音频编解码器。你要让它干活,就得先通过I2C总线给它写寄存器。我刚开始接触这颗芯片时,觉得寄存器手册密密麻麻的,头都大了。后来发现,其实核心的就那么几个——Reset、Power、Interface。把这几个搞定,音频通路基本就通了。
3.1 I2C控制接口初始化
WM8960的I2C地址是固定的:0x1A(7位地址)。如果你用HAL库,初始化代码其实很简单。我个人习惯把I2C的初始化封装成一个函数,方便复用。
// WM8960 I2C地址(7位)
#define WM8960_I2C_ADDR 0x1A
// I2C句柄,由CubeMX生成
extern I2C_HandleTypeDef hi2c1;
/**
* @brief 向WM8960写入一个寄存器
* @param reg: 寄存器地址(8位)
* @param val: 寄存器值(8位)
* @retval HAL_OK 表示成功
*/
HAL_StatusTypeDef WM8960_WriteReg(uint8_t reg, uint8_t val)
{
uint8_t data[2] = {reg, val};
return HAL_I2C_Master_Transmit(&hi2c1,
WM8960_I2C_ADDR << 1,
data, 2, 100);
}
初始化I2C外设本身,CubeMX已经帮我们做了。你只需要确保:
- I2C时钟频率不超过400kHz(WM8960支持标准模式和快速模式)
- SCL和SDA引脚的上拉电阻已配置(内部上拉通常不够,建议外部4.7kΩ)
- I2C外设已使能,且GPIO模式设置为开漏输出
3.2 核心寄存器配置流程
WM8960的寄存器地址范围是0x00~0x3F,共64个。但实际项目中,你不需要全部配置。我总结了一套“三步走”流程:Reset → Power → Interface。按这个顺序来,基本不会出错。
- Reset(复位):让芯片回到已知状态
- Power(电源管理):打开需要的模块,关闭不用的
- Interface(音频接口):配置I2S格式、位宽、采样率
下面这张图,是我画的核心配置流程。你跟着走一遍,心里就有谱了。
3.3 第一步:复位寄存器(0x0F)
复位寄存器地址是0x0F。写入0x00即可触发软件复位。为什么先做这一步?因为芯片上电后,内部状态是不确定的。复位一下,所有寄存器回到默认值,心里踏实。
// 复位WM8960
WM8960_WriteReg(0x0F, 0x00);
HAL_Delay(10); // 等待复位完成
3.4 第二步:电源管理寄存器(0x19, 0x1A)
电源管理是WM8960配置里最灵活的部分。两个寄存器控制着所有模拟模块的开关:
| 寄存器 | 地址 | 关键位 | 功能 |
|---|---|---|---|
| Power 1 | 0x19 | BIT6 (MICB), BIT5 (VMID), BIT0 (DIGEN) | 麦克风偏置、VMID缓冲、数字核心 |
| Power 2 | 0x1A | BIT7 (HPR), BIT6 (HPL), BIT5 (SPK), BIT0 (OUT3) | 耳机输出、扬声器输出、辅助输出 |
对于全双工录放音项目,我建议这样配置:
// 电源管理配置(全双工模式)
// Power 1 (0x19): 开启数字核心、VMID、麦克风偏置
WM8960_WriteReg(0x19, 0xBF); // 0b10111111
// Power 2 (0x1A): 开启左右耳机输出
WM8960_WriteReg(0x1A, 0xC0); // 0b11000000
这里解释一下关键位的含义:
- DIGEN (BIT0):数字核心电源。不开这个,芯片不工作。
- VMID (BIT5):中间电压缓冲。模拟电路需要这个参考电压。
- MICB (BIT6):麦克风偏置。如果你要用板载麦克风,必须开。
- HPL/HPR (BIT6/BIT7):左右耳机通道。全双工模式下,耳机用于监听。
3.5 第三步:音频接口寄存器(0x07)
音频接口寄存器0x07,是WM8960与STM32之间通信的“协议约定”。你需要告诉芯片:我们用I2S格式、数据位宽是多少、主从模式怎么选。
寄存器0x07的位定义如下:
| 位 | 名称 | 说明 |
|---|---|---|
| BIT7:6 | Format | 00=I2S, 01=Left-justified, 10=PCM, 11=Reserved |
| BIT5:4 | WL | 00=16bit, 01=20bit, 10=24bit, 11=32bit |
| BIT3 | LRSWAP | 0=正常, 1=左右声道交换 |
| BIT2 | LRP | 左右声道极性(通常置0) |
| BIT1:0 | MS | 00=从模式, 11=主模式 |
我们的项目里,STM32做主设备,WM8960做从设备。I2S格式,16位数据。配置代码很简单:
// 音频接口配置:I2S格式,16位,从模式
// 0x07 = 0b00000010 = 0x02
WM8960_WriteReg(0x07, 0x02);
为什么是0x02?你看:
- BIT7:6 = 00 → I2S格式
- BIT5:4 = 00 → 16位
- BIT3 = 0 → 正常声道
- BIT2 = 0 → 正常极性
- BIT1:0 = 10 → 从模式
嗯,这里要注意:从模式意味着WM8960的BCLK和LRCLK都由STM32提供。如果你配成主模式,WM8960会自己产生时钟,那STM32就得跟着它跑,反而麻烦。
3.6 完整的初始化序列
把上面三步串起来,就是WM8960的初始化函数。我个人习惯把它放在一个单独的文件里,比如wm8960.c。
/**
* @brief WM8960初始化(全双工模式)
* @retval HAL_OK 表示成功
*/
HAL_StatusTypeDef WM8960_Init(void)
{
HAL_StatusTypeDef ret;
// 1. 复位
ret = WM8960_WriteReg(0x0F, 0x00);
if (ret != HAL_OK) return ret;
HAL_Delay(10);
// 2. 电源管理
ret = WM8960_WriteReg(0x19, 0xBF); // Power 1
if (ret != HAL_OK) return ret;
ret = WM8960_WriteReg(0x1A, 0xC0); // Power 2
if (ret != HAL_OK) return ret;
// 3. 音频接口
ret = WM8960_WriteReg(0x07, 0x02); // I2S, 16bit, Slave
if (ret != HAL_OK) return ret;
return HAL_OK;
}
3.7 验证配置是否成功
配置写完了,怎么知道芯片有没有正确响应?我常用的方法是回读寄存器。WM8960支持读操作,你可以读一下刚写进去的寄存器,看看值对不对。
/**
* @brief 从WM8960读取一个寄存器
* @param reg: 寄存器地址
* @retval 寄存器值,0xFF表示读取失败
*/
uint8_t WM8960_ReadReg(uint8_t reg)
{
uint8_t val = 0;
HAL_I2C_Master_Transmit(&hi2c1, WM8960_I2C_ADDR << 1, ®, 1, 100);
HAL_I2C_Master_Receive(&hi2c1, WM8960_I2C_ADDR << 1, &val, 1, 100);
return val;
}
// 验证:读取音频接口寄存器,应为0x02
uint8_t check = WM8960_ReadReg(0x07);
if (check == 0x02) {
// 配置成功
} else {
// 配置失败,检查I2C连接
}
如果读回来的值跟你写的不一样,先别急着怀疑芯片。检查一下:
- I2C地址对不对?左移了没?
- 上拉电阻焊了没?
- WM8960的供电正常吗?(3.3V数字、1.5V模拟核心)