123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- #include "include.h"
- #define TRACE_EN 1
- #if TRACE_EN
- #define TRACE(...) printf(__VA_ARGS__)
- #else
- #define TRACE(...)
- #endif
- #if I2S_DEVICE == I2S_DEV_WM8978 && I2S_EN
- u16 wm8978_reg[58];
- static const u16 tbl_wm8978_reg[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
- };
- AT(.text.bsp.i2s)
- static void wm8978_write_one_byte(u8 addr, u8 dat)
- {
- bsp_i2c_start();
- bsp_i2c_tx_byte(0x34);
- bsp_i2c_rx_ack();
- bsp_i2c_tx_byte(addr);
- bsp_i2c_rx_ack();
- bsp_i2c_tx_byte(dat);
- bsp_i2c_rx_ack();
- bsp_i2c_stop();
- }
- AT(.text.bsp.i2s)
- static void wm8978_sfr_write(u8 addr, u16 dat)
- {
- wm8978_write_one_byte((addr << 1) | ((dat >> 8) & 0x01), (u8)dat);
- wm8978_reg[addr] = dat;
- }
- AT(.text.bsp.i2s)
- static u16 wm8978_sfr_read(u8 addr)
- {
- return wm8978_reg[addr];
- }
- AT(.text.bsp.i2s)
- static void wm8978_reset(void)
- {
- wm8978_sfr_write(0, 0);
- memcpy(wm8978_reg, tbl_wm8978_reg, sizeof(tbl_wm8978_reg));
- }
- //设置喇叭音量, voll:左声道音量(0~63)
- void wm8978_speaker_vol(u8 vol)
- {
- vol &= 0x3f;
- if (vol ==0) {
- vol |= 1<<6; //音量为0时,直接mute
- }
- wm8978_sfr_write(54, vol); //R54,喇叭左声道音量设置
- wm8978_sfr_write(55, vol | (1<<8)); //R55,喇叭右声道音量设置,同步更新(SPKVU=1)
- }
- //设置耳机左右声道音量
- //voll:左声道音量(0~63)
- //volr:右声道音量(0~63)
- void wm8978_hp_vol(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_sfr_write(52, voll); //R52,耳机左声道音量设置
- wm8978_sfr_write(53, volr|(1<<8)); //R53,耳机右声道音量设置,同步更新(HPVU=1)
- }
- //WM8978 MIC增益设置(不包括BOOST的20dB,MIC-->ADC输入部分的增益)
- //gain:0~63,对应-12dB~35.25dB,0.75dB/Step
- void wm8978_mic_gain(u8 gain)
- {
- gain &= 0x3f;
- wm8978_sfr_write(45, gain); //R45,左通道PGA设置
- wm8978_sfr_write(46, gain|1<<8); //R46,右通道PGA设置
- }
- //设置I2S工作模式
- //fmt:0,LSB(右对齐);1,MSB(左对齐);2,飞利浦标准I2S;3,PCM/DSP;
- //len:0,16位; 1,20位;2,24位; 3,32位;
- AT(.text.bsp.i2s)
- static void wm8978_i2s_cfg(u8 fmt, u8 len)
- {
- wm8978_sfr_write(4, ((fmt & 0x03)<<3)|((len & 0x03)<<5)); //R4, WM8978工作模式设置
- }
- //WM8978 DAC/ADC配置
- //adcen:adc使能(1)/关闭(0)
- //dacen:dac使能(1)/关闭(0)
- AT(.text.bsp.i2s)
- void wm8978_audio_cfg(u8 dacen, u8 adcen)
- {
- uint16_t regval;
- regval = wm8978_sfr_read(3); //读取R3
- if (dacen) {
- regval |= 3 << 0; //R3最低2个位设置为1,开启DACR&DACL
- } else {
- regval &= ~(3 << 0); //R3最低2个位清零,关闭DACR&DACL.
- }
- wm8978_sfr_write(3, regval); //设置R3
- regval = wm8978_sfr_read(2); //读取R2
- if (adcen) {
- regval |= 3 << 0; //R2最低2个位设置为1,开启ADCR&ADCL
- } else {
- regval &= ~(3 << 0); //R2最低2个位清零,关闭ADCR&ADCL.
- }
- wm8978_sfr_write(2, regval); //设置R2
- }
- //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_sfr_write(50, regval); //R50设置
- wm8978_sfr_write(51, regval); //R51设置
- }
- //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_sfr_read(47); //读取R47
- regval &= ~(7<<4); //清除原来的设置
- wm8978_sfr_write(47, regval|gain<<4); //设置R47
- regval = wm8978_sfr_read(48); //读取R48
- regval &= ~(7<<4); //清除原来的设置
- wm8978_sfr_write(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)
- {
- uint16_t regval;
- gain &= 0x07;
- regval = wm8978_sfr_read(47); //读取R47
- regval &= ~(7<<0); //清除原来的设置
- wm8978_sfr_write(47, regval|gain<<0); //设置R47
- regval = wm8978_sfr_read(48); //读取R48
- regval &= ~(7<<0); //清除原来的设置
- wm8978_sfr_write(48, regval|gain<<0); //设置R48
- }
- //WM8978 输入通道配置
- //micen:MIC开启(1)/关闭(0)
- //lineinen:Line In开启(1)/关闭(0)
- //auxen:aux开启(1)/关闭(0)
- void wm8978_input_cfg(u8 micen, u8 lineinen, u8 auxen)
- {
- uint16_t regval;
- regval = wm8978_sfr_read(2); //读取R2
- if (micen) {
- regval |= 3 << 2; //开启INPPGAENR,INPPGAENL(MIC的PGA放大)
- } else {
- regval &= ~(3 << 2); //关闭INPPGAENR,INPPGAENL.
- }
- wm8978_sfr_write(2, regval); //设置R2
- regval = wm8978_sfr_read(44); //读取R44
- if (micen) {
- regval |= 3<<4|3<<0; //开启LIN2INPPGA,LIP2INPGA,RIN2INPPGA,RIP2INPGA.
- } else {
- regval &= ~(3<<4|3<<0); //关闭LIN2INPPGA,LIP2INPGA,RIN2INPPGA,RIP2INPGA.
- }
- wm8978_sfr_write(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输入
- }
- }
- AT(.text.bsp.i2s)
- void wm8978_init(void)
- {
- TRACE("wm8978 start...\n");
- I2C_SDA_SCL_OUT();
- I2C_SDA_H();
- delay_5ms(1);
- wm8978_reset();
- #if I2S_MODE_SEL == 0
- wm8978_sfr_write(1, 0x1B); //R1,MICEN设置为1(MIC使能),BIASEN设置为1(模拟器工作),VMIDSEL[1:0]设置为:11(5K)
- wm8978_sfr_write(2, 0x1B0); //R2,ROUT1,LOUT1输出使能(耳机可以工作),BOOSTENR,BOOSTENL使能
- wm8978_sfr_write(3, 0x6C); //R3,LOUT2,ROUT2输出使能(喇叭工作),RMIX,LMIX使能
- wm8978_sfr_write(6, 0); //R6,MCLK由外部提供
- wm8978_sfr_write(43, BIT(4)); //R43,INVROUT2反向,驱动喇叭
- wm8978_sfr_write(47, BIT(8)); //R47设置,PGABOOSTL,左通道MIC获得20倍增益
- wm8978_sfr_write(48, BIT(8)); //R48设置,PGABOOSTR,右通道MIC获得20倍增益
- wm8978_sfr_write(49, BIT(1)); //R49,TSDEN,开启过热保护
- wm8978_sfr_write(10, BIT(3)); //R10,SOFTMUTE关闭,128x采样,最佳SNR
- wm8978_sfr_write(14, BIT(3)); //R14,ADC 128x采样率
- wm8978_i2s_cfg(2, 3); //设置I2S接口模式,播放从设备不使用
- //播放设置
- wm8978_audio_cfg(1, 0); //开启DAC
- wm8978_input_cfg(0, 0, 0); //关闭输入通道
- wm8978_output_cfg(1, 0); //开启DAC输出
- wm8978_hp_vol(25, 25);
- #else
- wm8978_sfr_write(1, 0x1B); //R1,MICEN设置为1(MIC使能),BIASEN设置为1(模拟器工作),VMIDSEL[1:0]设置为:11(5K)
- wm8978_sfr_write(2, 0x1B0); //R2,ROUT1,LOUT1输出使能(耳机可以工作),BOOSTENR,BOOSTENL使能
- wm8978_sfr_write(3, 0x6C); //R3,LOUT2,ROUT2输出使能(喇叭工作),RMIX,LMIX使能
- wm8978_sfr_write(6, 2 << 2 | 1); //R6
- wm8978_sfr_write(43, BIT(4)); //R43,INVROUT2反向,驱动喇叭
- wm8978_sfr_write(47, BIT(8)); //R47设置,PGABOOSTL,左通道MIC获得20倍增益
- wm8978_sfr_write(48, BIT(8)); //R48设置,PGABOOSTR,右通道MIC获得20倍增益
- wm8978_sfr_write(49, BIT(1)); //R49,TSDEN,开启过热保护
- wm8978_sfr_write(10, BIT(3)); //R10,SOFTMUTE关闭,128x采样,最佳SNR
- wm8978_sfr_write(14, BIT(3)); //R14,ADC 128x采样率
- wm8978_i2s_cfg(2, 0); //设置I2S接口模式,播放从设备不使用
- //播放设置
- wm8978_audio_cfg(0, 1); //开启ADC
- wm8978_input_cfg(0, 1, 0); //开启输入通道
- wm8978_output_cfg(0, 1); //开启ADC
- //wm8978_speaker_vol(30);
- // wm8978_mic_gain(6);
- #endif
- }
- #endif
|