360 lines
11 KiB
C
360 lines
11 KiB
C
#include "iic.h"
|
|
#include "wm8978.h"
|
|
|
|
extern tbool r_ack(void);
|
|
//--------------------------------------------------------------------------------
|
|
#define IIC_Init iic_init_io
|
|
#define IIC_Start iic_start
|
|
#define IIC_Stop iic_stop
|
|
#define IIC_Send_Byte iic_sendbyte_io
|
|
#define IIC_Wait_Ack r_ack
|
|
|
|
|
|
|
|
|
|
//WM8978寄存器值缓存区(总共58个寄存器,0~57),占用116字节内存
|
|
//因为WM8978的IIC操作不支持读操作,所以在本地保存所有寄存器值
|
|
//写WM8978寄存器时,同步更新到本地寄存器值,读寄存器时,直接返回本地保存的寄存器值.
|
|
//注意:WM8978的寄存器值是9位的,所以要用u16来存储.
|
|
static u16 WM8978_REGVAL_TBL[58] = {
|
|
0X0000, 0X0000, 0X0000, 0X0000, 0X0050, 0X0000, 0X0140, 0X0000,
|
|
0X0000, 0X0000, 0X0000, 0X00FF, 0X00FF, 0X0000, 0X0100, 0X00FF,
|
|
0X00FF, 0X0000, 0X012C, 0X002C, 0X002C, 0X002C, 0X002C, 0X0000,
|
|
0X0032, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000,
|
|
0X0038, 0X000B, 0X0032, 0X0000, 0X0008, 0X000C, 0X0093, 0X00E9,
|
|
0X0000, 0X0000, 0X0000, 0X0000, 0X0003, 0X0010, 0X0010, 0X0100,
|
|
0X0100, 0X0002, 0X0001, 0X0001, 0X0039, 0X0039, 0X0039, 0X0039,
|
|
0X0001, 0X0001
|
|
};
|
|
|
|
//WM8978写寄存器
|
|
//reg:寄存器地址
|
|
//val:要写入寄存器的值
|
|
//返回值:0,成功;
|
|
// 其他,错误代码
|
|
u8 WM8978_Write_Reg(u8 reg, u16 val)
|
|
{
|
|
IIC_Start();
|
|
IIC_Send_Byte((WM8978_ADDR << 1) | 0); //发送器件地址+写命令
|
|
if (IIC_Wait_Ack()) {
|
|
return 1; //等待应答(成功?/失败?)
|
|
}
|
|
IIC_Send_Byte((reg << 1) | ((val >> 8) & 0X01)); //写寄存器地址+数据的最高位
|
|
if (IIC_Wait_Ack()) {
|
|
return 2; //等待应答(成功?/失败?)
|
|
}
|
|
IIC_Send_Byte(val & 0XFF); //发送数据
|
|
if (IIC_Wait_Ack()) {
|
|
return 3; //等待应答(成功?/失败?)
|
|
}
|
|
IIC_Stop();
|
|
WM8978_REGVAL_TBL[reg] = val; //保存寄存器值到本地
|
|
return 0;
|
|
}
|
|
|
|
//WM8978初始化
|
|
//返回值:0,初始化正常
|
|
//其他,错误代码
|
|
u8 WM8978_Init(u8 dacen, u8 adcen)
|
|
{
|
|
u8 res;
|
|
IIC_Init();//初始化IIC接口
|
|
|
|
int i = 10;
|
|
while (--i) {
|
|
res = WM8978_Write_Reg(0, 0); //软复位WM8978
|
|
if (!res) {
|
|
printf("wm8978 reset ok,i=%d\n", i);
|
|
break;
|
|
} else {
|
|
printf("wm8978 cmu err!!!\n");
|
|
}
|
|
delay(50000);
|
|
}
|
|
if (0 == i) {
|
|
printf("Rest WM8978 10 times FAIL\n");
|
|
return 1;
|
|
}
|
|
|
|
//以下为通用设置
|
|
WM8978_Write_Reg(1, 0X1B); //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, 0X6C); //R3,LOUT2,ROUT2输出使能(喇叭工作),RMIX,LMIX使能
|
|
WM8978_Write_Reg(6, 0); //R6,MCLK由外部提供
|
|
WM8978_Write_Reg(43, 1 << 4); //R43,INVROUT2反向,驱动喇叭
|
|
WM8978_Write_Reg(47, 0 << 8); //R47设置,PGABOOSTL,左通道MIC获得20倍增益
|
|
WM8978_Write_Reg(48, 0 << 8); //R48设置,PGABOOSTR,右通道MIC获得20倍增益
|
|
WM8978_Write_Reg(49, 1 << 1); //R49,TSDEN,开启过热保护
|
|
WM8978_Write_Reg(10, 1 << 3); //R10,SOFTMUTE关闭,128x采样,最佳SNR
|
|
WM8978_Write_Reg(14, 1 << 3); //R14,ADC 128x采样率
|
|
|
|
|
|
//
|
|
delay(10000);
|
|
WM8978_HPvol_Set(30, 30); //耳机音量设置
|
|
WM8978_SPKvol_Set(60); //喇叭音量设置
|
|
delay(10000);
|
|
WM8978_ADDA_Cfg(dacen, adcen); //开启DAC
|
|
WM8978_Input_Cfg(adcen, 0, 0); //关闭输入通道
|
|
WM8978_Output_Cfg(dacen, adcen); //开启DAC输出
|
|
delay(10000);
|
|
WM8978_I2S_Cfg(2, 0); //飞利浦标准,16位数据长度
|
|
WM8978_MIC_Gain(63);
|
|
|
|
printf("WM8978_Init Finish\n");
|
|
return 0;
|
|
}
|
|
|
|
|
|
//WM8978读寄存器
|
|
//就是读取本地寄存器值缓冲区内的对应值
|
|
//reg:寄存器地址
|
|
//返回值:寄存器值
|
|
u16 WM8978_Read_Reg(u8 reg)
|
|
{
|
|
return WM8978_REGVAL_TBL[reg];
|
|
}
|
|
//WM8978 DAC/ADC配置
|
|
//adcen:adc使能(1)/关闭(0)
|
|
//dacen:dac使能(1)/关闭(0)
|
|
void WM8978_ADDA_Cfg(u8 dacen, u8 adcen)
|
|
{
|
|
u16 regval;
|
|
regval = WM8978_Read_Reg(3); //读取R3
|
|
if (dacen) {
|
|
regval |= 3 << 0; //R3最低2个位设置为1,开启DACR&DACL
|
|
} else {
|
|
regval &= ~(3 << 0); //R3最低2个位清零,关闭DACR&DACL.
|
|
}
|
|
WM8978_Write_Reg(3, regval); //设置R3
|
|
regval = WM8978_Read_Reg(2); //读取R2
|
|
if (adcen) {
|
|
regval |= 3 << 0; //R2最低2个位设置为1,开启ADCR&ADCL
|
|
} else {
|
|
regval &= ~(3 << 0); //R2最低2个位清零,关闭ADCR&ADCL.
|
|
}
|
|
WM8978_Write_Reg(2, regval); //设置R2
|
|
}
|
|
//WM8978 输入通道配置
|
|
//micen:MIC开启(1)/关闭(0)
|
|
//lineinen:Line In开启(1)/关闭(0)
|
|
//auxen:aux开启(1)/关闭(0)
|
|
void WM8978_Input_Cfg(u8 micen, u8 lineinen, u8 auxen)
|
|
{
|
|
u16 regval;
|
|
regval = WM8978_Read_Reg(2); //读取R2
|
|
if (micen) {
|
|
regval |= 3 << 2; //开启INPPGAENR,INPPGAENL(MIC的PGA放大)
|
|
} else {
|
|
regval &= ~(3 << 2); //关闭INPPGAENR,INPPGAENL.
|
|
}
|
|
WM8978_Write_Reg(2, regval); //设置R2
|
|
|
|
regval = WM8978_Read_Reg(44); //读取R44
|
|
if (micen) {
|
|
regval |= 3 << 4 | 3 << 0; //开启LIN2INPPGA,LIP2INPGA,RIN2INPPGA,RIP2INPGA.
|
|
} else {
|
|
regval &= ~(3 << 4 | 3 << 0); //关闭LIN2INPPGA,LIP2INPGA,RIN2INPPGA,RIP2INPGA.
|
|
}
|
|
WM8978_Write_Reg(44, regval); //设置R44
|
|
|
|
if (lineinen) {
|
|
WM8978_LINEIN_Gain(5); //LINE IN 0dB增益
|
|
} else {
|
|
WM8978_LINEIN_Gain(0); //关闭LINE IN
|
|
}
|
|
if (auxen) {
|
|
WM8978_AUX_Gain(7); //AUX 6dB增益
|
|
} else {
|
|
WM8978_AUX_Gain(0); //关闭AUX输入
|
|
}
|
|
}
|
|
//WM8978 输出配置
|
|
//dacen:DAC输出(放音)开启(1)/关闭(0)
|
|
//bpsen:Bypass输出(录音,包括MIC,LINE IN,AUX等)开启(1)/关闭(0)
|
|
void WM8978_Output_Cfg(u8 dacen, u8 bpsen)
|
|
{
|
|
u16 regval = 0;
|
|
if (dacen) {
|
|
regval |= 1 << 0; //DAC输出使能
|
|
}
|
|
if (bpsen) {
|
|
regval |= 1 << 1; //BYPASS使能
|
|
regval |= 5 << 2; //0dB增益
|
|
}
|
|
WM8978_Write_Reg(50, regval); //R50设置
|
|
WM8978_Write_Reg(51, regval); //R51设置
|
|
}
|
|
//WM8978 MIC增益设置(不包括BOOST的20dB,MIC-->ADC输入部分的增益)
|
|
//gain:0~63,对应-12dB~35.25dB,0.75dB/Step
|
|
void WM8978_MIC_Gain(u8 gain)
|
|
{
|
|
gain &= 0X3F;
|
|
WM8978_Write_Reg(45, gain); //R45,左通道PGA设置
|
|
WM8978_Write_Reg(46, gain | 1 << 8); //R46,右通道PGA设置
|
|
}
|
|
//WM8978 L2/R2(也就是Line In)增益设置(L2/R2-->ADC输入部分的增益)
|
|
//gain:0~7,0表示通道禁止,1~7,对应-12dB~6dB,3dB/Step
|
|
void WM8978_LINEIN_Gain(u8 gain)
|
|
{
|
|
u16 regval;
|
|
gain &= 0X07;
|
|
regval = WM8978_Read_Reg(47); //读取R47
|
|
regval &= ~(7 << 4); //清除原来的设置
|
|
WM8978_Write_Reg(47, regval | gain << 4); //设置R47
|
|
regval = WM8978_Read_Reg(48); //读取R48
|
|
regval &= ~(7 << 4); //清除原来的设置
|
|
WM8978_Write_Reg(48, regval | gain << 4); //设置R48
|
|
}
|
|
//WM8978 AUXR,AUXL(PWM音频部分)增益设置(AUXR/L-->ADC输入部分的增益)
|
|
//gain:0~7,0表示通道禁止,1~7,对应-12dB~6dB,3dB/Step
|
|
void WM8978_AUX_Gain(u8 gain)
|
|
{
|
|
u16 regval;
|
|
gain &= 0X07;
|
|
regval = WM8978_Read_Reg(47); //读取R47
|
|
regval &= ~(7 << 0); //清除原来的设置
|
|
WM8978_Write_Reg(47, regval | gain << 0); //设置R47
|
|
regval = WM8978_Read_Reg(48); //读取R48
|
|
regval &= ~(7 << 0); //清除原来的设置
|
|
WM8978_Write_Reg(48, regval | gain << 0); //设置R48
|
|
}
|
|
//设置I2S工作模式
|
|
//fmt:0,LSB(右对齐);1,MSB(左对齐);2,飞利浦标准I2S;3,PCM/DSP;
|
|
//len:0,16位;1,20位;2,24位;3,32位;
|
|
void WM8978_I2S_Cfg(u8 fmt, u8 len)
|
|
{
|
|
fmt &= 0X03;
|
|
len &= 0X03; //限定范围
|
|
WM8978_Write_Reg(4, (fmt << 3) | (len << 5)); //R4,WM8978工作模式设置
|
|
}
|
|
|
|
//设置耳机左右声道音量
|
|
//voll:左声道音量(0~63)
|
|
//volr:右声道音量(0~63)
|
|
void WM8978_HPvol_Set(u8 voll, u8 volr)
|
|
{
|
|
voll &= 0X3F;
|
|
volr &= 0X3F; //限定范围
|
|
if (voll == 0) {
|
|
voll |= 1 << 6; //音量为0时,直接mute
|
|
}
|
|
if (volr == 0) {
|
|
volr |= 1 << 6; //音量为0时,直接mute
|
|
}
|
|
WM8978_Write_Reg(52, voll); //R52,耳机左声道音量设置
|
|
WM8978_Write_Reg(53, volr | (1 << 8)); //R53,耳机右声道音量设置,同步更新(HPVU=1)
|
|
}
|
|
//设置喇叭音量
|
|
//voll:左声道音量(0~63)
|
|
void WM8978_SPKvol_Set(u8 volx)
|
|
{
|
|
volx &= 0X3F; //限定范围
|
|
if (volx == 0) {
|
|
volx |= 1 << 6; //音量为0时,直接mute
|
|
}
|
|
WM8978_Write_Reg(54, volx); //R54,喇叭左声道音量设置
|
|
WM8978_Write_Reg(55, volx | (1 << 8)); //R55,喇叭右声道音量设置,同步更新(SPKVU=1)
|
|
}
|
|
//设置3D环绕声
|
|
//depth:0~15(3D强度,0最弱,15最强)
|
|
void WM8978_3D_Set(u8 depth)
|
|
{
|
|
depth &= 0XF; //限定范围
|
|
WM8978_Write_Reg(41, depth); //R41,3D环绕设置
|
|
}
|
|
//设置EQ/3D作用方向
|
|
//dir:0,在ADC起作用
|
|
// 1,在DAC起作用(默认)
|
|
void WM8978_EQ_3D_Dir(u8 dir)
|
|
{
|
|
u16 regval;
|
|
regval = WM8978_Read_Reg(0X12);
|
|
if (dir) {
|
|
regval |= 1 << 8;
|
|
} else {
|
|
regval &= ~(1 << 8);
|
|
}
|
|
WM8978_Write_Reg(18, regval); //R18,EQ1的第9位控制EQ/3D方向
|
|
}
|
|
|
|
//设置EQ1
|
|
//cfreq:截止频率,0~3,分别对应:80/105/135/175Hz
|
|
//gain:增益,0~24,对应-12~+12dB
|
|
void WM8978_EQ1_Set(u8 cfreq, u8 gain)
|
|
{
|
|
u16 regval;
|
|
cfreq &= 0X3; //限定范围
|
|
if (gain > 24) {
|
|
gain = 24;
|
|
}
|
|
gain = 24 - gain;
|
|
regval = WM8978_Read_Reg(18);
|
|
regval &= 0X100;
|
|
regval |= cfreq << 5; //设置截止频率
|
|
regval |= gain; //设置增益
|
|
WM8978_Write_Reg(18, regval); //R18,EQ1设置
|
|
}
|
|
//设置EQ2
|
|
//cfreq:中心频率,0~3,分别对应:230/300/385/500Hz
|
|
//gain:增益,0~24,对应-12~+12dB
|
|
void WM8978_EQ2_Set(u8 cfreq, u8 gain)
|
|
{
|
|
u16 regval = 0;
|
|
cfreq &= 0X3; //限定范围
|
|
if (gain > 24) {
|
|
gain = 24;
|
|
}
|
|
gain = 24 - gain;
|
|
regval |= cfreq << 5; //设置截止频率
|
|
regval |= gain; //设置增益
|
|
WM8978_Write_Reg(19, regval); //R19,EQ2设置
|
|
}
|
|
//设置EQ3
|
|
//cfreq:中心频率,0~3,分别对应:650/850/1100/1400Hz
|
|
//gain:增益,0~24,对应-12~+12dB
|
|
void WM8978_EQ3_Set(u8 cfreq, u8 gain)
|
|
{
|
|
u16 regval = 0;
|
|
cfreq &= 0X3; //限定范围
|
|
if (gain > 24) {
|
|
gain = 24;
|
|
}
|
|
gain = 24 - gain;
|
|
regval |= cfreq << 5; //设置截止频率
|
|
regval |= gain; //设置增益
|
|
WM8978_Write_Reg(20, regval); //R20,EQ3设置
|
|
}
|
|
//设置EQ4
|
|
//cfreq:中心频率,0~3,分别对应:1800/2400/3200/4100Hz
|
|
//gain:增益,0~24,对应-12~+12dB
|
|
void WM8978_EQ4_Set(u8 cfreq, u8 gain)
|
|
{
|
|
u16 regval = 0;
|
|
cfreq &= 0X3; //限定范围
|
|
if (gain > 24) {
|
|
gain = 24;
|
|
}
|
|
gain = 24 - gain;
|
|
regval |= cfreq << 5; //设置截止频率
|
|
regval |= gain; //设置增益
|
|
WM8978_Write_Reg(21, regval); //R21,EQ4设置
|
|
}
|
|
//设置EQ5
|
|
//cfreq:中心频率,0~3,分别对应:5300/6900/9000/11700Hz
|
|
//gain:增益,0~24,对应-12~+12dB
|
|
void WM8978_EQ5_Set(u8 cfreq, u8 gain)
|
|
{
|
|
u16 regval = 0;
|
|
cfreq &= 0X3; //限定范围
|
|
if (gain > 24) {
|
|
gain = 24;
|
|
}
|
|
gain = 24 - gain;
|
|
regval |= cfreq << 5; //设置截止频率
|
|
regval |= gain; //设置增益
|
|
WM8978_Write_Reg(22, regval); //R22,EQ5设置
|
|
}
|
|
|
|
|