本文主要是介绍stm32开发之wm8978驱动记录(rt-thread),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
头文件
//
// Created by shchl on 2024/3/11.
//#ifndef F4_OS_AUDIO_WM8978_H
#define F4_OS_AUDIO_WM8978_H#include "rtdevice.h"#define WM8978_ADDR 0X1A //WM8978的器件地址,固定为0X1A(7bit 地址)
struct audio_wm8978 {struct rt_i2c_bus_device *bus; /*总线指针*/uint8_t addr; /*地址*/rt_mutex_t lock; /*互斥锁*/
};typedef struct audio_wm8978 *audio_wm8978_t;audio_wm8978_t wm8978_init(char *bus_name, uint8_t addr);rt_err_t wm8978_cnf_init();void wm8978_deInit(audio_wm8978_t wm8978);rt_err_t wm8978_set_reg(audio_wm8978_t wm8978, uint8_t reg, uint16_t val);uint16_t wm8978_read_reg(uint8_t reg);void wm8978_ADDA_Cfg(uint8_t dacen, uint8_t adcen);void wm8978_Input_Cfg(uint8_t micen, uint8_t lineinen, uint8_t auxen);void wm8978_Output_Cfg(uint8_t dacen, uint8_t bpsen);void wm8978_MIC_Gain(uint8_t gain);void wm8978_LINEIN_Gain(uint8_t gain);void wm8978_AUX_Gain(uint8_t gain);void wm8978_I2S_Cfg(uint8_t fmt, uint8_t len);void wm8978_HPvol_Set(uint8_t voll, uint8_t volr);void wm8978_SPKvol_Set(uint8_t volx);void wm8978_3D_Set(uint8_t depth);void wm8978_EQ_3D_Dir(uint8_t dir);void wm8978_EQ1_Set(uint8_t cfreq, uint8_t gain);void wm8978_EQ2_Set(uint8_t cfreq, uint8_t gain);void wm8978_EQ3_Set(uint8_t cfreq, uint8_t gain);void wm8978_EQ4_Set(uint8_t cfreq, uint8_t gain);void wm8978_EQ5_Set(uint8_t cfreq, uint8_t gain);#endif //F4_OS_AUDIO_WM8978_H
源文件
//
// Created by shchl on 2024/3/11.
//
#include "audio_wm8978.h"
#include <rtthread.h>#define DBG_ENABLE
#define DBG_TAG "wm8978"
#define DBG_LVL DBG_LOG#include <rtdbg.h>static audio_wm8978_t device = NULL;
//WM8978寄存器值缓存区(总共58个寄存器,0~57),占用116字节内存
//因为WM8978的IIC操作不支持读操作,所以在本地保存所有寄存器值
//写WM8978寄存器时,同步更新到本地寄存器值,读寄存器时,直接返回本地保存的寄存器值.
//注意:WM8978的寄存器值是9位的,所以要用uint16_t来存储.
static uint16_t 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};static rt_err_t write_reg(uint8_t reg, uint16_t val) {return wm8978_set_reg(device, reg, val);
}rt_err_t wm8978_set_reg(audio_wm8978_t wm8978, uint8_t reg, uint16_t val) {rt_uint8_t buf[2];buf[0] = (reg << 1) | ((val >> 8) & 0X01);buf[1] = val & 0XFF;if (wm8978 == NULL) {LOG_E("请先执行 wm8978_init");return RT_ERROR;}if (rt_i2c_master_send(wm8978->bus, wm8978->addr, RT_I2C_WR, buf, 2) != 2) {return RT_ERROR;}wm8978_REGVAL_TBL[reg] = val; //保存寄存器值到本地return RT_EOK;
}/*** 初始化 wm8978* @param bus_name 总线名* @param addr 地址(7位地址)* @return*/
audio_wm8978_t wm8978_init(char *bus_name, uint8_t addr) {RT_ASSERT(bus_name);device = rt_calloc(1, sizeof(struct audio_wm8978));if (device == RT_NULL) {LOG_E("Can't allocate memory for audio_wm8978 device on '%s' ", bus_name);return RT_NULL;}device->bus = rt_i2c_bus_device_find(bus_name);if (device->bus == RT_NULL) {LOG_E("Can't find audio_wm8978 device on '%s' ", bus_name);rt_free(device);return RT_NULL;}device->lock = rt_mutex_create("mutex_wm8978", RT_IPC_FLAG_FIFO);if (device->lock == RT_NULL) {LOG_E("Can't create mutex for audio_wm8978 device on '%s' ", bus_name);rt_free(device);return RT_NULL;}{device->bus->timeout = 3;/*尝试3次*/device->addr = addr;}return device;
}void wm8978_deInit(audio_wm8978_t wm8978) {if (wm8978 != NULL) {if (wm8978 == device) {rt_free(wm8978);}}
}/*** 配置初始化* @param wm8978*/
rt_err_t wm8978_cnf_init() {if (write_reg(0, 0) != RT_EOK) return RT_ERROR; //软复位WM8978发送指令失败,WM8978异常//以下为通用设置write_reg(1, 0X1B); //R1,MICEN设置为1(MIC使能),BIASEN设置为1(模拟器工作),VMIDSEL[1:0]设置为:11(5K)write_reg(2, 0X1B0); //R2,ROUT1,LOUT1输出使能(耳机可以工作),BOOSTENR,BOOSTENL使能write_reg(3, 0X6C); //R3,LOUT2,ROUT2输出使能(喇叭工作),RMIX,LMIX使能write_reg(6, 0); //R6,MCLK由外部提供write_reg(43, 1 << 4); //R43,INVROUT2反向,驱动喇叭write_reg(47, 1 << 8); //R47设置,PGABOOSTL,左通道MIC获得20倍增益write_reg(48, 1 << 8); //R48设置,PGABOOSTR,右通道MIC获得20倍增益write_reg(49, 1 << 1); //R49,TSDEN,开启过热保护write_reg(49, 1 << 2); //R49,SPEAKER BOOST,1.5xwrite_reg(10, 1 << 3); //R10,SOFTMUTE关闭,128x采样,最佳SNRwrite_reg(14, 1 << 3); //R14,ADC 128x采样率return RT_EOK;
}//WM8978读寄存器
//就是读取本地寄存器值缓冲区内的对应值
//reg:寄存器地址
//返回值:寄存器值
uint16_t wm8978_read_reg(uint8_t reg) {return wm8978_REGVAL_TBL[reg];
}//WM8978 DAC/ADC配置
//adcen:adc使能(1)/关闭(0)
//dacen:dac使能(1)/关闭(0)
void wm8978_ADDA_Cfg(uint8_t dacen, uint8_t adcen) {uint16_t regval;regval = wm8978_read_reg(3); //读取R3if (dacen)regval |= 3 << 0; //R3最低2个位设置为1,开启DACR&DACLelse regval &= ~(3 << 0); //R3最低2个位清零,关闭DACR&DACL.write_reg(3, regval); //设置R3regval = wm8978_read_reg(2); //读取R2if (adcen)regval |= 3 << 0; //R2最低2个位设置为1,开启ADCR&ADCLelse regval &= ~(3 << 0); //R2最低2个位清零,关闭ADCR&ADCL.write_reg(2, regval); //设置R2
}//WM8978 输入通道配置
//micen:MIC开启(1)/关闭(0)
//lineinen:Line In开启(1)/关闭(0)
//auxen:aux开启(1)/关闭(0)
void wm8978_Input_Cfg(uint8_t micen, uint8_t lineinen, uint8_t auxen) {uint16_t regval;regval = wm8978_read_reg(2); //读取R2if (micen)regval |= 3 << 2; //开启INPPGAENR,INPPGAENL(MIC的PGA放大)else regval &= ~(3 << 2); //关闭INPPGAENR,INPPGAENL.write_reg(2, regval); //设置R2regval = wm8978_read_reg(44); //读取R44if (micen)regval |= 3 << 4 | 3 << 0; //开启LIN2INPPGA,LIP2INPGA,RIN2INPPGA,RIP2INPGA.else regval &= ~(3 << 4 | 3 << 0); //关闭LIN2INPPGA,LIP2INPGA,RIN2INPPGA,RIP2INPGA.write_reg(44, regval);//设置R44if (lineinen)wm8978_LINEIN_Gain(5);//LINE IN 0dB增益else wm8978_LINEIN_Gain(0); //关闭LINE INif (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(uint8_t dacen, uint8_t bpsen) {uint16_t regval = 0;if (dacen)regval |= 1 << 0; //DAC输出使能if (bpsen) {regval |= 1 << 1; //BYPASS使能regval |= 5 << 2; //0dB增益}write_reg(50, regval);//R50设置write_reg(51, regval);//R51设置
}//WM8978 MIC增益设置(不包括BOOST的20dB,MIC-->ADC输入部分的增益)
//gain:0~63,对应-12dB~35.25dB,0.75dB/Step
void wm8978_MIC_Gain(uint8_t gain) {gain &= 0X3F;write_reg(45, gain); //R45,左通道PGA设置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(uint8_t gain) {uint16_t regval;gain &= 0X07;regval = wm8978_read_reg(47); //读取R47regval &= ~(7 << 4); //清除原来的设置write_reg(47, regval | gain << 4);//设置R47regval = wm8978_read_reg(48); //读取R48regval &= ~(7 << 4); //清除原来的设置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(uint8_t gain) {uint16_t regval;gain &= 0X07;regval = wm8978_read_reg(47); //读取R47regval &= ~(7 << 0); //清除原来的设置write_reg(47, regval | gain << 0);//设置R47regval = wm8978_read_reg(48); //读取R48regval &= ~(7 << 0); //清除原来的设置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(uint8_t fmt, uint8_t len) {fmt &= 0X03;len &= 0X03;//限定范围write_reg(4, (fmt << 3) | (len << 5)); //R4,WM8978工作模式设置
}//设置耳机左右声道音量
//voll:左声道音量(0~63)
//volr:右声道音量(0~63)
void wm8978_HPvol_Set(uint8_t voll, uint8_t volr) {voll &= 0X3F;volr &= 0X3F;//限定范围if (voll == 0)voll |= 1 << 6;//音量为0时,直接muteif (volr == 0)volr |= 1 << 6;//音量为0时,直接mutewrite_reg(52, voll); //R52,耳机左声道音量设置write_reg(53, volr | (1 << 8)); //R53,耳机右声道音量设置,同步更新(HPVU=1)
}//设置喇叭音量
//voll:左声道音量(0~63)
void wm8978_SPKvol_Set(uint8_t volx) {volx &= 0X3F;//限定范围if (volx == 0)volx |= 1 << 6;//音量为0时,直接mutewrite_reg(54, volx); //R54,喇叭左声道音量设置write_reg(55, volx | (1 << 8)); //R55,喇叭右声道音量设置,同步更新(SPKVU=1)
}//设置3D环绕声
//depth:0~15(3D强度,0最弱,15最强)
void wm8978_3D_Set(uint8_t depth) {depth &= 0XF;//限定范围write_reg(41, depth); //R41,3D环绕设置
}//设置EQ/3D作用方向
//dir:0,在ADC起作用
// 1,在DAC起作用(默认)
void wm8978_EQ_3D_Dir(uint8_t dir) {uint16_t regval;regval = wm8978_read_reg(0X12);if (dir)regval |= 1 << 8;else regval &= ~(1 << 8);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(uint8_t cfreq, uint8_t gain) {uint16_t regval;cfreq &= 0X3;//限定范围if (gain > 24)gain = 24;gain = 24 - gain;regval = wm8978_read_reg(18);regval &= 0X100;regval |= cfreq << 5; //设置截止频率regval |= gain; //设置增益write_reg(18, regval);//R18,EQ1设置
}//设置EQ2
//cfreq:中心频率,0~3,分别对应:230/300/385/500Hz
//gain:增益,0~24,对应-12~+12dB
void wm8978_EQ2_Set(uint8_t cfreq, uint8_t gain) {uint16_t regval = 0;cfreq &= 0X3;//限定范围if (gain > 24)gain = 24;gain = 24 - gain;regval |= cfreq << 5; //设置截止频率regval |= gain; //设置增益write_reg(19, regval);//R19,EQ2设置
}//设置EQ3
//cfreq:中心频率,0~3,分别对应:650/850/1100/1400Hz
//gain:增益,0~24,对应-12~+12dB
void wm8978_EQ3_Set(uint8_t cfreq, uint8_t gain) {uint16_t regval = 0;cfreq &= 0X3;//限定范围if (gain > 24)gain = 24;gain = 24 - gain;regval |= cfreq << 5; //设置截止频率regval |= gain; //设置增益write_reg(20, regval);//R20,EQ3设置
}//设置EQ4
//cfreq:中心频率,0~3,分别对应:1800/2400/3200/4100Hz
//gain:增益,0~24,对应-12~+12dB
void wm8978_EQ4_Set(uint8_t cfreq, uint8_t gain) {uint16_t regval = 0;cfreq &= 0X3;//限定范围if (gain > 24)gain = 24;gain = 24 - gain;regval |= cfreq << 5; //设置截止频率regval |= gain; //设置增益write_reg(21, regval);//R21,EQ4设置
}//设置EQ5
//cfreq:中心频率,0~3,分别对应:5300/6900/9000/11700Hz
//gain:增益,0~24,对应-12~+12dB
void wm8978_EQ5_Set(uint8_t cfreq, uint8_t gain) {uint16_t regval = 0;cfreq &= 0X3;//限定范围if (gain > 24)gain = 24;gain = 24 - gain;regval |= cfreq << 5; //设置截止频率regval |= gain; //设置增益write_reg(22, regval);//R22,EQ5设置
}
这篇关于stm32开发之wm8978驱动记录(rt-thread)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!