接前一篇文章:STM32H743VIT6使用STM32CubeMX通过I2S驱动WM8978(1)
本文参考以下文章及视频:
STM32CbueIDE Audio播放音频 WM8978 + I2S_stm32 cube配置i2s录音和播放-CSDN博客
STM32第二十二课(I2S,HAL,cubemx)_i2s cubemax-CSDN博客
STM32:I2S驱动WM8978_stm32 iis输出-CSDN博客
STM32:利用VM8978和I2S实现录音的频率分析-CSDN博客
第35讲-I2S 6(配套例程讲解)_哔哩哔哩_bilibili
第83讲 音乐播放器实验讲解_哔哩哔哩_bilibili
特此致谢!
上一回开始讲解WM8978的第一个函数即初始化函数wm8978_init。讲了WM8978的复位函数,也就是对于寄存器0的配置操作,本文接下来讲解对于其它寄存器的配置。
为了便于理解和回顾,再次贴出正点原子和野火的代码,分别如下:
- 正点原子代码
//WM8978初始化
//返回值:0,初始化正常
// 其它,错误代码
u8 WM8978_Init(void)
{
u8 res;
IIC_Init(); //初始化I2C接口
res = WM8978_Write_Reg(0, 0); //软复位WM8978
if(res) //发送指令失败,WM8978异常
return 1;
//以下为通用设置
WM8978_Write_Reg(1, 0x01B); //R1,MICEN设置为1(MIC使能),BIASEN设置为1(模拟器工作),VMIDSEL[1:0]设置为11(5K)
WM8978_Write_Reg(2, 0x1B0); //R2,ROUT1、LOUT1输出使能(耳机可以工作),BOOSTENR、BOOSTENL使能
WM8978_Write_Reg(3, 0x06C); //R3,LOUT2、ROUT2输出使能(喇叭工作),RMIX、LMIX使能
WM8978_Write_Reg(6, 0); //R6,MCLK由外部提供
WM8978_Write_Reg(43, 1<<4); //R43,INVROUT2反向,驱动喇叭
WM8978_Write_Reg(47, 1<<8); //R47,PGABOOSTL,左通道MIC获得20倍增益
WM8978_Write_Reg(48, 1<<8); //R48,PGABOOSTR,右通道MIC获得20倍增益
WM8978_Write_Reg(49, 1<<1); //R49,TSDEN,开启过热保护
WM8978_Write_Reg(49, 1<<2); //R49,SPEAKER BOOST,1.5x
WM8978_Write_Reg(10, 1<<3); //R10,SOFTMUTE关闭,128x采样,最佳SNR(信噪比)
WM8978_Write_Reg(14, 1<<3); //R14,ADC 128x采样率
return 0;
}
- 野火代码
/**
* @brief 配置I2C GPIO,并检查I2C总线上的WM8978是否正常
* @param 无
* @retval 1,初始化成功
* 0,初始化失败
*/
uint8_t wm8978_Init(void)
{
uint8_t res;
I2cMaster_Init(); //初始化I2C接口
res = wm8978_Reset(); //硬件复位WM8978所有寄存器到缺省状态
wm8978_CtrlGPIO1(1); //控制WM8978的一个GPIO接口,控制其为放音状态
return res;
}
/**
* @brief 复位wm8978
* @param 无
* @retval 1:复位成功
* 0:复位失败
*/
uint8_t wm8978_Reset(void)
{
//wm8978寄存器缺省值
const uint16_t reg_default[] = {
0x000, 0x000, 0x000, 0x000, 0x050, 0x000, 0x140, 0x000,
0x000, 0x000, 0x000, 0x0FF, 0x0FF, 0x000, 0x100, 0x0FF,
0x0FF, 0x000, 0x12C, 0x02C, 0x02C, 0x02C, 0x02C, 0x000,
0x032, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x038, 0x00B, 0x032, 0x000, 0x008, 0x00C, 0x093, 0x0E9,
0x000, 0x000, 0x000, 0x000, 0x003, 0x010, 0x010, 0x100,
0x100, 0x002, 0x001, 0x001, 0x039, 0x039, 0x039, 0x039,
0x001, 0x001
};
uint8_t res;
uint8_t i;
res = wm8978_WriteReg(0x00, 0);
for (i = 0; i < sizeof(reg_default) / 2; i++)
wm8978_RegCash[i] = reg_default[i];
return res;
}
//WM8978寄存器缓存
//由于WM8978的I2C两线接口不支持读取操作,因此寄存器值缓存在内存中
//当写寄存器同步更新缓存,读寄存器时直接返回缓存中的值
static uint16_t wm8978_RegCash[] = {
0x000, 0x000, 0x000, 0x000, 0x050, 0x000, 0x140, 0x000,
0x000, 0x000, 0x000, 0x0FF, 0x0FF, 0x000, 0x100, 0x0FF,
0x0FF, 0x000, 0x12C, 0x02C, 0x02C, 0x02C, 0x02C, 0x000,
0x032, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x038, 0x00B, 0x032, 0x000, 0x008, 0x00C, 0x093, 0x0E9,
0x000, 0x000, 0x000, 0x000, 0x003, 0x010, 0x010, 0x100,
0x100, 0x002, 0x001, 0x001, 0x039, 0x039, 0x039, 0x039,
0x001, 0x001
};
寄存器1
- 正点原子代码
WM8978_Write_Reg(1, 0x01B); //R1,MICEN设置为1(MIC使能),BIASEN设置为1(模拟器工作),VMIDSEL[1:0]设置为11(5K)
- 野火代码
void wm8978_CfgAudioPath(uint16_t _InPath, uint16_t _OutPath)
{
uint16_t usReg;
//查看WM8978数据手册的 REGISTER MAP 章节,第89页
if ((_InPath == IN_PATH_OFF) && (_OutPath == OUT_PATH_OFF))
{
wm8978_PowerDown();
return;
}
//第1步:根据输入通道参数配置寄存器
//
// R1 寄存器 Power manage 1
// Bit8 BUFDCOPEN,Output stage 1.5xAVDD/2 driver enable
// Bit7 OUT4MIXEN,OUT4 mixer enable
// Bit6 OUT3MIXEN,OUT3 mixer enable
// Bit5 PLLEN,不用
// Bit4 MICBEN,Microphone Bias Enable (MIC偏置电路使能)
// Bit3 BIASEN,Analogue amplifier bias control必须设置为1,模拟放大器才工作
// Bit2 BUFIOEN,Unused input/output tie off buffer enable
// Bit1:0 VMIDSEL,必须设置为非00值,模拟放大器才工作
//
usReg = (1 << 3) | (3 << 0);
if (_OutPath & OUT3_4_ON) //OUT3和OUT4使能输出GSM模块
{
usReg |= ((1 << 7) | (1 << 6));
}
if ((_InPath & MIC_LEFT_ON) || (_InPath & MIC_RIGHT_ON))
{
usReg |= (1 << 4);
}
wm8978_WriteReg(1, usReg); //写寄存器
……
}
由正点原子和野火代码的对比可以看到,正点原子的代码简单直接,给出了注释,一目了然;而野火的代码则并不是单独的一句,而是放在了一个更大的函数中(此函数相当于正点原子代码的初始化函数中那许多行代码),这样的代码更优雅、也更正规,也更为全面,函数功能划分也更清楚。总的来说,这两家的代码各有所长。
关于寄存器1的说明,参见笔者文章:WM8978 —— 带扬声器驱动程序的立体声编解码器(4)-CSDN博客
寄存器1复位默认值为0x000(0b000000000)。
VMID和BIASEN的说明参见WM8978手册第79页,如下:
同时参见WM8978手册第34页,如下:
寄存器2
- 正点原子代码
WM8978_Write_Reg(2, 0x1B0); //R2,ROUT1、LOUT1输出使能(耳机可以工作),BOOSTENR、BOOSTENL使能
- 野火代码
void wm8978_CfgAudioPath(uint16_t _InPath, uint16_t _OutPath)
{
uint16_t usReg;
//查看WM8978数据手册的 REGISTER MAP 章节,第89页
if ((_InPath == IN_PATH_OFF) && (_OutPath == OUT_PATH_OFF))
{
wm8978_PowerDown();
return;
}
//第1步:根据输入通道参数配置寄存器
……
//
// R2 寄存器 Power manage 2
// Bit8 ROUT1EN,ROUT1 output enable 耳机右声道输出使能
// Bit7 LOUT1EN,LOUT1 output enable 耳机左声道输出使能
// Bit6 SLEEP,0 = Normal device operation 1 = Residual current reduced in device standby mode
// Bit5 BOOSTENR,Right channel Input BOOST enable 右通道输入自举电路使能
// Bit4 BOOSTENL,Left channel Input BOOST enable 左通道输入自举电路使能
// Bit3 INPGAENR,Right channel input PGA enable 右声道输入PGA使能
// Bit2 INPGAENL,Left channel input PGA enable 左声道输入PGA使能
// Bit1 ADCENR,Enable ADC right channel
// Bit0 ADCENL,Enable ADC left channel
//
usReg = 0;
if (_OutPath & EAR_LEFT_ON)
{
usReg |= (1 << 7);
}
if (_OutPath & EAR_RIGHT_ON)
{
usReg |= (1 << 8);
}
if (_InPath & MIC_LEFT_ON)
{
usReg |= ((1 << 4) | (1 << 2));
}
if (_InPath & MIC_RIGHT_ON)
{
usReg |= ((1 << 5) | (1 << 3));
}
if (_InPath & LINE_ON)
{
usReg |= ((1 << 4) | (1 << 5));
}
if (_InPath & MIC_RIGHT_ON)
{
usReg |= ((1 << 5) | (1 << 3));
}
if (_InPath & ADC_ON)
{
usReg |= ((1 << 1) | (1 << 0));
}
wm8978_WriteReg(2, usReg); //写寄存器
……
}
这里不再对正点原子和野火两家代码进行比较(上边已经说得比较清楚了),而重点说明具体的配置实现的功能。
关于寄存器2的说明,参见笔者文章:WM8978 —— 带扬声器驱动程序的立体声编解码器(4)-CSDN博客
寄存器2复位默认值为0x000(0b000000000)。
- ROUT1EN和LOUT1EN
参见WM8978手册第63页,如下:
同时参见WM8978手册第52页,如下:
- SLEEP
参见WM8978手册第63页,如下:
- BOOSTENR和BOOSTENL
参见WM8978手册第33页,如下:
同时参见WM8978手册第32页,如下:
- INPPGAENR和INPPGAENL
参见WM8978手册第28页,如下:
同时参见WM8978手册第27页,如下:
- ADCENR和ADCENL
参见WM8978手册第35页,如下:
同时参见WM8978手册第35页,如下:
更多寄存器配置的详细说明与讲解请看下回。