/
wm8978.c
401 lines (362 loc) · 12 KB
/
wm8978.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
#include "wm8978.h"
#include "hal_i2c.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "hal_i2s.h"
#define bit0 0x001
#define bit1 0x002
#define bit2 0x004
#define bit3 0x008
#define bit4 0x010
#define bit5 0x020
#define bit6 0x040
#define bit7 0x080
#define bit8 0x100
//////////////////////////////////////////////////////////////////////////////////
//????????ѧϰʹ???δ??????ɣ??????????????
//ALIENTEK STM32F407??????
//WM8978 ??????
//?????@ALIENTEK
//????̳:www.openedv.com
//??????:2014/5/24
//?汾??V1.0
//???????????????
//Copyright(C) ???????ӿƼ?????˾ 2014-2024
//All rights reserved
//////////////////////////////////////////////////////////////////////////////////
typedef struct
{
char rld[4]; //riff 标志符号
int rLen; //
char wld[4]; //格式类型(wave)
char fld[4]; //"fmt"
int fLen; //sizeof(wave format matex)
short wFormatTag; //编码格式
short wChannels; //声道数
int nSamplesPersec; //采样频率
int nAvgBitsPerSample;//WAVE文件采样大小
short wBlockAlign; //块对齐
short wBitsPerSample; //WAVE文件采样大小
char dld[4]; //”data“
int wSampleLength; //音频数据的大小
}WAV_HEADER;
//WM8978?Ĵ??ֵ?????(???58???Ĵ??,0~57),ռ?116???ڴ?
//?ΪWM8978??IC?????֧?ֶ????,??????ر??????Ĵ??ֵ
//д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 void wm8979_interface()
{
WM8978_REGVAL_TBL[WM8978_AUDIO_INTERFACE] &=~(bit6|bit5);//16bit
//WM8978_REGVAL_TBL[WM8978_AUDIO_INTERFACE]|=(bit6|bit5);//32bit
WM8978_Write_Reg(WM8978_AUDIO_INTERFACE,WM8978_REGVAL_TBL[WM8978_AUDIO_INTERFACE]);
WM8978_REGVAL_TBL[WM8978_CLOCKING]|=bit0; //the codec ic is master mode
WM8978_REGVAL_TBL[WM8978_CLOCKING]|=bit3|bit2;// 256/32=8
WM8978_REGVAL_TBL[WM8978_CLOCKING]&=~(bit7|bit6|bit5); //mclk=mclk
WM8978_REGVAL_TBL[WM8978_CLOCKING]|=bit6;
WM8978_REGVAL_TBL[WM8978_CLOCKING]|=bit8;
WM8978_Write_Reg(WM8978_CLOCKING,WM8978_REGVAL_TBL[WM8978_CLOCKING]);
//WM8978_REGVAL_TBL[WM8978_CLOCKING]&=~bit8;//mclk is the clk source
}
static void wm8979_pll(uint32_t k,uint8_t n)
{
WM8978_REGVAL_TBL[WM8978_POWER_MANAGEMENT_1]|=bit5;//enable pll
WM8978_Write_Reg(WM8978_POWER_MANAGEMENT_1,WM8978_REGVAL_TBL[WM8978_POWER_MANAGEMENT_1]);
WM8978_REGVAL_TBL[WM8978_PLL_N]|=bit4;//mclk/2 =20m
WM8978_REGVAL_TBL[WM8978_PLL_N]&=0x1f0;
WM8978_REGVAL_TBL[WM8978_PLL_N]|=n;//7
WM8978_Write_Reg(WM8978_PLL_N,WM8978_REGVAL_TBL[WM8978_PLL_N]);
//k=EE009F
WM8978_REGVAL_TBL[WM8978_PLL_K1]=(k>>18);
WM8978_Write_Reg(WM8978_PLL_K1,WM8978_REGVAL_TBL[WM8978_PLL_K1]);
WM8978_REGVAL_TBL[WM8978_PLL_K2]=(k>>9);
WM8978_Write_Reg(WM8978_PLL_K2,WM8978_REGVAL_TBL[WM8978_PLL_K2]);
WM8978_REGVAL_TBL[WM8978_PLL_K3]=k;
WM8978_Write_Reg(WM8978_PLL_K3,WM8978_REGVAL_TBL[WM8978_PLL_K3]);
}
static void wm8979_loopback()
{
WM8978_REGVAL_TBL[WM8978_COMPANDING_CONTROL]|=bit0; //start loopback
WM8978_Write_Reg(WM8978_COMPANDING_CONTROL,WM8978_REGVAL_TBL[WM8978_COMPANDING_CONTROL]);
}
//WM8978 init
//返回值:0,初始化正常
// 其他,错误代码
uint8_t WM8978_Init(void)
{
//??Ϊͨ???
wm8979_pll(0x86c227,0x07);
wm8979_interface();
WM8978_Write_Reg(1,0X3B); //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ʹ? //0x6c
//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(10,1<<3); //R10,SOFTMUTE?ر?128x???,???NR
WM8978_Write_Reg(14,1<<3); //R14,ADC 128x????
//wm8979_loopback();
return 0;
}
//WM8978写寄存器
//reg:寄存器地址
//val:要写入寄存器的值
//返回值:0,成功;
//其他,错误代码
uint8_t WM8978_Write_Reg(uint8_t reg,uint16_t val)
{
uint8_t buf[2];
buf[0]=((val&0x0100)>>8)|(reg<<1);
buf[1]=(uint8_t)(val&0xff);
hal_i2c_master_mem_write(0,WM8978_ADDR,buf[0],buf+1,1);
WM8978_REGVAL_TBL[reg]=val;
return 0;
}
// WM8978 read register
// Reads the value of the local register buffer zone
// reg: Register Address
// Return Value: Register value
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); //??ȡR3
if(dacen)regval|=3<<0; //R3?????λ??Ϊ1,???DACR&DACL
else regval&=~(3<<0); //R3?????λ????ر?ACR&DACL.
WM8978_Write_Reg(3,regval); //??R3
regval=WM8978_Read_Reg(2); //??ȡR2
if(adcen)regval|=3<<0; //R2?????λ??Ϊ1,???ADCR&ADCL
else regval&=~(3<<0); //R2?????λ????ر?DCR&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(uint8_t micen,uint8_t lineinen,uint8_t auxen)
{
uint16_t regval;
regval=WM8978_Read_Reg(2); //??ȡR2
if(micen)regval|=3<<2; //???INPPGAENR,INPPGAENL(MIC??GA?Ŵ?
else regval&=~(3<<2); //?ر?NPPGAENR,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); //?ر?IN2INPPGA,LIP2INPGA,RIN2INPPGA,RIP2INPGA.
WM8978_Write_Reg(44,regval);//??R44
if(lineinen)WM8978_LINEIN_Gain(5);//LINE IN 0dB??
else WM8978_LINEIN_Gain(0); //?ر?INE IN
if(auxen)WM8978_AUX_Gain(7);//AUX 6dB??
else WM8978_AUX_Gain(0); //?ر?UX??
}
//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??
}
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(uint8_t 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(uint8_t gain)
{
uint16_t 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
}
void aplay(char* filename){
//"/sdcard/test.wav"
WAV_HEADER wav_head;
FILE* f = fopen(filename, "r");
if (f == NULL) {
printf("Failed to open file for writing");
return;
}
//fprintf(f, "Hello %s!\n", card->cid.name);
int rlen=fread(&wav_head,1,sizeof(wav_head),f);
if(rlen!=sizeof(wav_head)){
printf("%s\n","read faliled");
return;
}
int channels = wav_head.wChannels;
int frequency = wav_head.nSamplesPersec;
int bit = wav_head.wBitsPerSample;
int datalen= wav_head.wSampleLength;
printf("channels:%d,frequency:%d,bit:%d\n",channels,frequency,bit);
char* samples_data = malloc(1024);
while(datalen){
rlen=fread(samples_data,1,1024,f);
datalen-=rlen;
hal_i2s_write(0,samples_data,rlen,5000);
}
fclose(f);
free(samples_data);
}
//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); //??ȡ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(uint8_t fmt,uint8_t 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(uint8_t voll,uint8_t volr)
{
voll&=0X3F;
volr&=0X3F;//?????Χ
if(voll==0)voll|=1<<6;//???Ϊ0ʱ,ֱ??ute
if(volr==0)volr|=1<<6;//???Ϊ0ʱ,ֱ??ute
WM8978_Write_Reg(52,voll); //R52,?????????????
WM8978_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ʱ,ֱ??ute
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(uint8_t depth)
{
depth&=0XF;//?????Χ
WM8978_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);
WM8978_Write_Reg(18,regval);//R18,EQ1?ĵ?λ???Q/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; //????
WM8978_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; //????
WM8978_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; //????
WM8978_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; //????
WM8978_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; //????
WM8978_Write_Reg(22,regval);//R22,EQ5??
}