wm8978.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. #include "include.h"
  2. #define TRACE_EN 1
  3. #if TRACE_EN
  4. #define TRACE(...) printf(__VA_ARGS__)
  5. #else
  6. #define TRACE(...)
  7. #endif
  8. #if I2S_DEVICE == I2S_DEV_WM8978 && I2S_EN
  9. u16 wm8978_reg[58];
  10. static const u16 tbl_wm8978_reg[58] = {
  11. 0x0000,0x0000,0x0000,0x0000,0x0050,0x0000,0x0140,0x0000,
  12. 0x0000,0x0000,0x0000,0x00FF,0x00FF,0x0000,0x0100,0x00FF,
  13. 0x00FF,0x0000,0x012C,0x002C,0x002C,0x002C,0x002C,0x0000,
  14. 0x0032,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  15. 0x0038,0x000B,0x0032,0x0000,0x0008,0x000C,0x0093,0x00E9,
  16. 0x0000,0x0000,0x0000,0x0000,0x0003,0x0010,0x0010,0x0100,
  17. 0x0100,0x0002,0x0001,0x0001,0x0039,0x0039,0x0039,0x0039,
  18. 0x0001,0x0001
  19. };
  20. AT(.text.bsp.i2s)
  21. static void wm8978_write_one_byte(u8 addr, u8 dat)
  22. {
  23. bsp_i2c_start();
  24. bsp_i2c_tx_byte(0x34);
  25. bsp_i2c_rx_ack();
  26. bsp_i2c_tx_byte(addr);
  27. bsp_i2c_rx_ack();
  28. bsp_i2c_tx_byte(dat);
  29. bsp_i2c_rx_ack();
  30. bsp_i2c_stop();
  31. }
  32. AT(.text.bsp.i2s)
  33. static void wm8978_sfr_write(u8 addr, u16 dat)
  34. {
  35. wm8978_write_one_byte((addr << 1) | ((dat >> 8) & 0x01), (u8)dat);
  36. wm8978_reg[addr] = dat;
  37. }
  38. AT(.text.bsp.i2s)
  39. static u16 wm8978_sfr_read(u8 addr)
  40. {
  41. return wm8978_reg[addr];
  42. }
  43. AT(.text.bsp.i2s)
  44. static void wm8978_reset(void)
  45. {
  46. wm8978_sfr_write(0, 0);
  47. memcpy(wm8978_reg, tbl_wm8978_reg, sizeof(tbl_wm8978_reg));
  48. }
  49. //设置喇叭音量, voll:左声道音量(0~63)
  50. void wm8978_speaker_vol(u8 vol)
  51. {
  52. vol &= 0x3f;
  53. if (vol ==0) {
  54. vol |= 1<<6; //音量为0时,直接mute
  55. }
  56. wm8978_sfr_write(54, vol); //R54,喇叭左声道音量设置
  57. wm8978_sfr_write(55, vol | (1<<8)); //R55,喇叭右声道音量设置,同步更新(SPKVU=1)
  58. }
  59. //设置耳机左右声道音量
  60. //voll:左声道音量(0~63)
  61. //volr:右声道音量(0~63)
  62. void wm8978_hp_vol(u8 voll, u8 volr)
  63. {
  64. voll &= 0x3f;
  65. volr &= 0x3f; //限定范围
  66. if (voll == 0) {
  67. voll |= 1<<6; //音量为0时,直接mute
  68. }
  69. if (volr == 0) {
  70. volr |= 1<<6; //音量为0时,直接mute
  71. }
  72. wm8978_sfr_write(52, voll); //R52,耳机左声道音量设置
  73. wm8978_sfr_write(53, volr|(1<<8)); //R53,耳机右声道音量设置,同步更新(HPVU=1)
  74. }
  75. //WM8978 MIC增益设置(不包括BOOST的20dB,MIC-->ADC输入部分的增益)
  76. //gain:0~63,对应-12dB~35.25dB,0.75dB/Step
  77. void wm8978_mic_gain(u8 gain)
  78. {
  79. gain &= 0x3f;
  80. wm8978_sfr_write(45, gain); //R45,左通道PGA设置
  81. wm8978_sfr_write(46, gain|1<<8); //R46,右通道PGA设置
  82. }
  83. //设置I2S工作模式
  84. //fmt:0,LSB(右对齐);1,MSB(左对齐);2,飞利浦标准I2S;3,PCM/DSP;
  85. //len:0,16位; 1,20位;2,24位; 3,32位;
  86. AT(.text.bsp.i2s)
  87. static void wm8978_i2s_cfg(u8 fmt, u8 len)
  88. {
  89. wm8978_sfr_write(4, ((fmt & 0x03)<<3)|((len & 0x03)<<5)); //R4, WM8978工作模式设置
  90. }
  91. //WM8978 DAC/ADC配置
  92. //adcen:adc使能(1)/关闭(0)
  93. //dacen:dac使能(1)/关闭(0)
  94. AT(.text.bsp.i2s)
  95. void wm8978_audio_cfg(u8 dacen, u8 adcen)
  96. {
  97. uint16_t regval;
  98. regval = wm8978_sfr_read(3); //读取R3
  99. if (dacen) {
  100. regval |= 3 << 0; //R3最低2个位设置为1,开启DACR&DACL
  101. } else {
  102. regval &= ~(3 << 0); //R3最低2个位清零,关闭DACR&DACL.
  103. }
  104. wm8978_sfr_write(3, regval); //设置R3
  105. regval = wm8978_sfr_read(2); //读取R2
  106. if (adcen) {
  107. regval |= 3 << 0; //R2最低2个位设置为1,开启ADCR&ADCL
  108. } else {
  109. regval &= ~(3 << 0); //R2最低2个位清零,关闭ADCR&ADCL.
  110. }
  111. wm8978_sfr_write(2, regval); //设置R2
  112. }
  113. //WM8978 输出配置
  114. //dacen:DAC输出(放音)开启(1)/关闭(0)
  115. //bpsen:Bypass输出(录音,包括MIC,LINE IN,AUX等)开启(1)/关闭(0)
  116. void wm8978_output_cfg(u8 dacen, u8 bpsen)
  117. {
  118. u16 regval = 0;
  119. if (dacen) {
  120. regval |= 1 << 0; //DAC输出使能
  121. }
  122. if (bpsen) {
  123. regval |= 1 << 1; //BYPASS使能
  124. regval |= 5 << 2; //0dB增益
  125. }
  126. wm8978_sfr_write(50, regval); //R50设置
  127. wm8978_sfr_write(51, regval); //R51设置
  128. }
  129. //WM8978 L2/R2(也就是Line In)增益设置(L2/R2-->ADC输入部分的增益)
  130. //gain:0~7,0表示通道禁止,1~7,对应-12dB~6dB,3dB/Step
  131. void wm8978_linein_gain(u8 gain)
  132. {
  133. u16 regval;
  134. gain &= 0x07;
  135. regval = wm8978_sfr_read(47); //读取R47
  136. regval &= ~(7<<4); //清除原来的设置
  137. wm8978_sfr_write(47, regval|gain<<4); //设置R47
  138. regval = wm8978_sfr_read(48); //读取R48
  139. regval &= ~(7<<4); //清除原来的设置
  140. wm8978_sfr_write(48, regval|gain<<4); //设置R48
  141. }
  142. //WM8978 AUXR,AUXL(PWM音频部分)增益设置(AUXR/L-->ADC输入部分的增益)
  143. //gain:0~7,0表示通道禁止,1~7,对应-12dB~6dB,3dB/Step
  144. void wm8978_aux_gain(u8 gain)
  145. {
  146. uint16_t regval;
  147. gain &= 0x07;
  148. regval = wm8978_sfr_read(47); //读取R47
  149. regval &= ~(7<<0); //清除原来的设置
  150. wm8978_sfr_write(47, regval|gain<<0); //设置R47
  151. regval = wm8978_sfr_read(48); //读取R48
  152. regval &= ~(7<<0); //清除原来的设置
  153. wm8978_sfr_write(48, regval|gain<<0); //设置R48
  154. }
  155. //WM8978 输入通道配置
  156. //micen:MIC开启(1)/关闭(0)
  157. //lineinen:Line In开启(1)/关闭(0)
  158. //auxen:aux开启(1)/关闭(0)
  159. void wm8978_input_cfg(u8 micen, u8 lineinen, u8 auxen)
  160. {
  161. uint16_t regval;
  162. regval = wm8978_sfr_read(2); //读取R2
  163. if (micen) {
  164. regval |= 3 << 2; //开启INPPGAENR,INPPGAENL(MIC的PGA放大)
  165. } else {
  166. regval &= ~(3 << 2); //关闭INPPGAENR,INPPGAENL.
  167. }
  168. wm8978_sfr_write(2, regval); //设置R2
  169. regval = wm8978_sfr_read(44); //读取R44
  170. if (micen) {
  171. regval |= 3<<4|3<<0; //开启LIN2INPPGA,LIP2INPGA,RIN2INPPGA,RIP2INPGA.
  172. } else {
  173. regval &= ~(3<<4|3<<0); //关闭LIN2INPPGA,LIP2INPGA,RIN2INPPGA,RIP2INPGA.
  174. }
  175. wm8978_sfr_write(44,regval); //设置R44
  176. if (lineinen) {
  177. wm8978_linein_gain(5); //LINE IN 0dB增益
  178. } else {
  179. wm8978_linein_gain(0); //关闭LINE IN
  180. }
  181. if (auxen) {
  182. wm8978_aux_gain(7); //AUX 6dB增益
  183. } else {
  184. wm8978_aux_gain(0); //关闭AUX输入
  185. }
  186. }
  187. AT(.text.bsp.i2s)
  188. void wm8978_init(void)
  189. {
  190. TRACE("wm8978 start...\n");
  191. I2C_SDA_SCL_OUT();
  192. I2C_SDA_H();
  193. delay_5ms(1);
  194. wm8978_reset();
  195. #if I2S_MODE_SEL == 0
  196. wm8978_sfr_write(1, 0x1B); //R1,MICEN设置为1(MIC使能),BIASEN设置为1(模拟器工作),VMIDSEL[1:0]设置为:11(5K)
  197. wm8978_sfr_write(2, 0x1B0); //R2,ROUT1,LOUT1输出使能(耳机可以工作),BOOSTENR,BOOSTENL使能
  198. wm8978_sfr_write(3, 0x6C); //R3,LOUT2,ROUT2输出使能(喇叭工作),RMIX,LMIX使能
  199. wm8978_sfr_write(6, 0); //R6,MCLK由外部提供
  200. wm8978_sfr_write(43, BIT(4)); //R43,INVROUT2反向,驱动喇叭
  201. wm8978_sfr_write(47, BIT(8)); //R47设置,PGABOOSTL,左通道MIC获得20倍增益
  202. wm8978_sfr_write(48, BIT(8)); //R48设置,PGABOOSTR,右通道MIC获得20倍增益
  203. wm8978_sfr_write(49, BIT(1)); //R49,TSDEN,开启过热保护
  204. wm8978_sfr_write(10, BIT(3)); //R10,SOFTMUTE关闭,128x采样,最佳SNR
  205. wm8978_sfr_write(14, BIT(3)); //R14,ADC 128x采样率
  206. wm8978_i2s_cfg(2, 3); //设置I2S接口模式,播放从设备不使用
  207. //播放设置
  208. wm8978_audio_cfg(1, 0); //开启DAC
  209. wm8978_input_cfg(0, 0, 0); //关闭输入通道
  210. wm8978_output_cfg(1, 0); //开启DAC输出
  211. wm8978_hp_vol(25, 25);
  212. #else
  213. wm8978_sfr_write(1, 0x1B); //R1,MICEN设置为1(MIC使能),BIASEN设置为1(模拟器工作),VMIDSEL[1:0]设置为:11(5K)
  214. wm8978_sfr_write(2, 0x1B0); //R2,ROUT1,LOUT1输出使能(耳机可以工作),BOOSTENR,BOOSTENL使能
  215. wm8978_sfr_write(3, 0x6C); //R3,LOUT2,ROUT2输出使能(喇叭工作),RMIX,LMIX使能
  216. wm8978_sfr_write(6, 2 << 2 | 1); //R6
  217. wm8978_sfr_write(43, BIT(4)); //R43,INVROUT2反向,驱动喇叭
  218. wm8978_sfr_write(47, BIT(8)); //R47设置,PGABOOSTL,左通道MIC获得20倍增益
  219. wm8978_sfr_write(48, BIT(8)); //R48设置,PGABOOSTR,右通道MIC获得20倍增益
  220. wm8978_sfr_write(49, BIT(1)); //R49,TSDEN,开启过热保护
  221. wm8978_sfr_write(10, BIT(3)); //R10,SOFTMUTE关闭,128x采样,最佳SNR
  222. wm8978_sfr_write(14, BIT(3)); //R14,ADC 128x采样率
  223. wm8978_i2s_cfg(2, 0); //设置I2S接口模式,播放从设备不使用
  224. //播放设置
  225. wm8978_audio_cfg(0, 1); //开启ADC
  226. wm8978_input_cfg(0, 1, 0); //开启输入通道
  227. wm8978_output_cfg(0, 1); //开启ADC
  228. //wm8978_speaker_vol(30);
  229. // wm8978_mic_gain(6);
  230. #endif
  231. }
  232. #endif