arduino-audio-driver
Loading...
Searching...
No Matches
WM8994.h
Go to the documentation of this file.
1
40#pragma once
41
42/* Includes ------------------------------------------------------------------*/
43// #include "../Common/audio.h"
44#include <stddef.h>
45#include <stdint.h>
46
48#include "DriverCommon.h"
49#include "Platforms/API_Delay.h"
50#include "Platforms/API_I2C.h"
51#include "stdbool.h"
52
53
54namespace audio_driver {
55
61class WM8994 {
62 public:
74 static constexpr uint16_t OUTPUT_DEVICE_SPEAKER = 0x0001;
75 static constexpr uint16_t OUTPUT_DEVICE_HEADPHONE = 0x0002;
76 static constexpr uint16_t OUTPUT_DEVICE_BOTH = 0x0003;
77 static constexpr uint16_t OUTPUT_DEVICE_AUTO = 0x0004;
78 static constexpr uint16_t INPUT_DEVICE_DIGITAL_MICROPHONE_1 = 0x0100;
79 static constexpr uint16_t INPUT_DEVICE_DIGITAL_MICROPHONE_2 = 0x0200;
80 static constexpr uint16_t INPUT_DEVICE_INPUT_LINE_1 = 0x0300;
81 static constexpr uint16_t INPUT_DEVICE_INPUT_LINE_2 = 0x0400;
82 static constexpr uint8_t DEFAULT_VOLMIN = 0x00;
83 static constexpr uint8_t DEFAULT_VOLMAX = 0xFF;
84 static constexpr uint8_t DEFAULT_VOLSTEP = 0x04;
85 static constexpr int AUDIO_PAUSE = 0;
86 static constexpr int AUDIO_RESUME = 1;
87 static constexpr int CODEC_PDWN_HW = 1;
88 static constexpr int CODEC_PDWN_SW = 2;
89 static constexpr int AUDIO_MUTE_ON = 1;
90 static constexpr int AUDIO_MUTE_OFF = 0;
91 static constexpr uint32_t WM8994_ID = 0x8994;
92 static constexpr uint16_t WM8994_CHIPID_ADDR = 0x00;
93 static constexpr int WM8994_ADDR = 0x1A;
94
95 WM8994() = default;
96
98 void setWire(i2c_bus_handle_t handle) { i2c_handle = handle; }
99
101 void setAddress(int addr) {
102 if (addr > 0) i2c_addr = addr;
103 }
104
115 uint32_t init(uint16_t OutputInputDevice, uint8_t Volume,
116 uint32_t AudioFreq) {
117 uint32_t counter = 0;
118 uint16_t output_device = OutputInputDevice & 0xFF;
119 uint16_t input_device = OutputInputDevice & 0xFF00;
120 uint16_t power_mgnt_reg_1 = 0;
121
122 /* wm8994 Errata Work-Arounds */
123 counter += writeReg16(0x102, 0x0003);
124 counter += writeReg16(0x817, 0x0000);
125 counter += writeReg16(0x102, 0x0000);
126
127 /* Enable VMID soft start (fast), Start-up Bias Current Enabled */
128 counter += writeReg16(0x39, 0x006C);
129
130 /* Enable bias generator, Enable VMID */
131 counter += writeReg16(0x01, 0x0003);
132
133 /* Add Delay - matches ST's reference exactly (wm8994.c), not scaled by
134 * family or cold/warm state. */
135 delayMs(50);
136
137 /* Path Configurations for output */
138 if (output_device > 0) {
139 output_enabled = 1;
140 switch (output_device) {
142 /* Enable DAC1 (Left), Enable DAC1 (Right),
143 Disable DAC2 (Left), Disable DAC2 (Right)*/
144 counter += writeReg16(0x05, 0x0C0C);
145
146 /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */
147 counter += writeReg16(0x601, 0x0000);
148
149 /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */
150 counter += writeReg16(0x602, 0x0000);
151
152 /* Disable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */
153 counter += writeReg16(0x604, 0x0002);
154
155 /* Disable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */
156 counter += writeReg16(0x605, 0x0002);
157 break;
158
160 /* Disable DAC1 (Left), Disable DAC1 (Right),
161 Enable DAC2 (Left), Enable DAC2 (Right)*/
162 counter += writeReg16(0x05, 0x0303);
163
164 /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */
165 counter += writeReg16(0x601, 0x0001);
166
167 /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */
168 counter += writeReg16(0x602, 0x0001);
169
170 /* Disable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */
171 counter += writeReg16(0x604, 0x0000);
172
173 /* Disable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */
174 counter += writeReg16(0x605, 0x0000);
175 break;
176
178 /* Enable DAC1 (Left), Enable DAC1 (Right),
179 also Enable DAC2 (Left), Enable DAC2 (Right)*/
180 counter += writeReg16(0x05, 0x0303 | 0x0C0C);
181
182 /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */
183 counter += writeReg16(0x601, 0x0001);
184
185 /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */
186 counter += writeReg16(0x602, 0x0001);
187
188 /* Enable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */
189 counter += writeReg16(0x604, 0x0002);
190
191 /* Enable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */
192 counter += writeReg16(0x605, 0x0002);
193 break;
194
196 default:
197 /* Disable DAC1 (Left), Disable DAC1 (Right),
198 Enable DAC2 (Left), Enable DAC2 (Right)*/
199 counter += writeReg16(0x05, 0x0303);
200
201 /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */
202 counter += writeReg16(0x601, 0x0001);
203
204 /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */
205 counter += writeReg16(0x602, 0x0001);
206
207 /* Disable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */
208 counter += writeReg16(0x604, 0x0000);
209
210 /* Disable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */
211 counter += writeReg16(0x605, 0x0000);
212 break;
213 }
214 } else {
215 output_enabled = 0;
216 }
217
218 /* Path Configurations for input */
219 if (input_device > 0) {
220 input_enabled = 1;
221 switch (input_device) {
223 /* Enable AIF1ADC2 (Left), Enable AIF1ADC2 (Right)
224 * Enable DMICDAT2 (Left), Enable DMICDAT2 (Right)
225 * Enable Left ADC, Enable Right ADC */
226 counter += writeReg16(0x04, 0x0C30);
227
228 /* Enable AIF1 DRC2 Signal Detect & DRC in AIF1ADC2 Left/Right Timeslot 1 */
229 counter += writeReg16(0x450, 0x00DB);
230
231 /* Disable IN1L, IN1R, IN2L, IN2R, Enable Thermal sensor & shutdown */
232 counter += writeReg16(0x02, 0x6000);
233
234 /* Enable the DMIC2(Left) to AIF1 Timeslot 1 (Left) mixer path */
235 counter += writeReg16(0x608, 0x0002);
236
237 /* Enable the DMIC2(Right) to AIF1 Timeslot 1 (Right) mixer path */
238 counter += writeReg16(0x609, 0x0002);
239
240 /* GPIO1 pin configuration GP1_DIR = output, GP1_FN = AIF1 DRC2 signal detect */
241 counter += writeReg16(0x700, 0x000E);
242 break;
243
245 /* Enable AIF1ADC1 (Left), Enable AIF1ADC1 (Right)
246 * Enable Left ADC, Enable Right ADC */
247 counter += writeReg16(0x04, 0x0303);
248
249 /* Enable AIF1 DRC1 Signal Detect & DRC in AIF1ADC1 Left/Right Timeslot 0 */
250 counter += writeReg16(0x440, 0x00DB);
251
252 /* Enable IN1L and IN1R, Disable IN2L and IN2R, Enable Thermal sensor & shutdown */
253 counter += writeReg16(0x02, 0x6350);
254
255 /* Enable the ADCL(Left) to AIF1 Timeslot 0 (Left) mixer path */
256 counter += writeReg16(0x606, 0x0002);
257
258 /* Enable the ADCR(Right) to AIF1 Timeslot 0 (Right) mixer path */
259 counter += writeReg16(0x607, 0x0002);
260
261 /* GPIO1 pin configuration GP1_DIR = output, GP1_FN = AIF1 DRC1 signal detect */
262 counter += writeReg16(0x700, 0x000D);
263 break;
264
267 default:
268 /* Actually, no other input devices supported */
269 counter++;
270 break;
271 }
272 } else {
273 input_enabled = 0;
274 }
275
276 /* Clock Configurations */
277 switch (AudioFreq) {
279 /* AIF1 Sample Rate = 8 (KHz), ratio=256 */
280 counter += writeReg16(0x210, 0x0003);
281 break;
282
284 /* AIF1 Sample Rate = 16 (KHz), ratio=256 */
285 counter += writeReg16(0x210, 0x0033);
286 break;
287
289 /* AIF1 Sample Rate = 48 (KHz), ratio=256 */
290 counter += writeReg16(0x210, 0x0083);
291 break;
292
294 /* AIF1 Sample Rate = 96 (KHz), ratio=256 */
295 counter += writeReg16(0x210, 0x00A3);
296 break;
297
299 /* AIF1 Sample Rate = 11.025 (KHz), ratio=256 */
300 counter += writeReg16(0x210, 0x0013);
301 break;
302
304 /* AIF1 Sample Rate = 22.050 (KHz), ratio=256 */
305 counter += writeReg16(0x210, 0x0043);
306 break;
307
309 /* AIF1 Sample Rate = 44.1 (KHz), ratio=256 */
310 counter += writeReg16(0x210, 0x0073);
311 break;
312
313 default:
314 /* AIF1 Sample Rate = 48 (KHz), ratio=256 */
315 counter += writeReg16(0x210, 0x0083);
316 break;
317 }
318 /* AIF1 Word Length = 16-bits, AIF1 Format = I2S (Default Register Value) */
319 counter += writeReg16(0x300, 0x4010);
320
321 /* slave mode */
322 counter += writeReg16(0x302, 0x0000);
323
324 /* Enable the DSP processing clock for AIF1, Enable the core clock */
325 counter += writeReg16(0x208, 0x000A);
326
327 /* Enable AIF1 Clock, AIF1 Clock Source = MCLK1 pin */
328 counter += writeReg16(0x200, 0x0001);
329
330 if (output_device > 0) /* Audio output selected */
331 {
332 if (output_device == OUTPUT_DEVICE_HEADPHONE) {
333 // Missing vs. the official ST BSP wm8994_Init(): without this, the
334 // headphone path never actually gets brought up by WM8994's internal
335 // write-sequencer, so I2C/DAC/mixer config can all succeed
336 // (indistinguishable in logs/DMA behavior) while HPOUT stays silent.
337
338 /* Select DAC1 (Left) to Left Headphone Output PGA (HPOUT1LVOL) path */
339 counter += writeReg16(0x2D, 0x0100);
340
341 /* Select DAC1 (Right) to Right Headphone Output PGA (HPOUT1RVOL) path */
342 counter += writeReg16(0x2E, 0x0100);
343
344 /* Startup sequence for Headphone - delays match ST's reference
345 * exactly (wm8994.c: 300ms cold / 50ms warm, no family scaling). */
346 if (is_cold_startup) {
347 counter += writeReg16(0x110, 0x8100);
348 is_cold_startup = false;
349 delayMs(300);
350 } else {
351 /* Headphone Warm Start-Up */
352 counter += writeReg16(0x110, 0x8108);
353 delayMs(50);
354 }
355
356 /* Soft un-Mute the AIF1 Timeslot 0 DAC1 path L&R */
357 counter += writeReg16(0x420, 0x0000);
358 }
359
360 /* Analog Output Configuration */
361
362 /* Enable SPKRVOL PGA, Enable SPKMIXR, Enable SPKLVOL PGA, Enable SPKMIXL */
363 counter += writeReg16(0x03, 0x0300);
364
365 /* Left Speaker Mixer Volume = 0dB */
366 counter += writeReg16(0x22, 0x0000);
367
368 /* Speaker output mode = Class D, Right Speaker Mixer Volume = 0dB ((0x23, 0x0100) = class AB)*/
369 counter += writeReg16(0x23, 0x0000);
370
371 /* Unmute DAC2 (Left) to Left Speaker Mixer (SPKMIXL) path,
372 Unmute DAC2 (Right) to Right Speaker Mixer (SPKMIXR) path */
373 counter += writeReg16(0x36, 0x0300);
374
375 /* Enable bias generator, Enable VMID, Enable SPKOUTL, Enable SPKOUTR */
376 counter += writeReg16(0x01, 0x3003);
377
378 /* Headphone/Speaker Enable */
379
380 /* Enable Class W, Class W Envelope Tracking = AIF1 Timeslot 0 */
381 counter += writeReg16(0x51, 0x0005);
382
383 /* Enable bias generator, Enable VMID, Enable HPOUT1 (Left) and Enable HPOUT1 (Right) input stages */
384 /* idem for Speaker */
385 power_mgnt_reg_1 |= 0x0303 | 0x3003;
386 counter += writeReg16(0x01, power_mgnt_reg_1);
387
388 /* Enable HPOUT1 (Left) and HPOUT1 (Right) intermediate stages */
389 counter += writeReg16(0x60, 0x0022);
390
391 /* Enable Charge Pump */
392 counter += writeReg16(0x4C, 0x9F25);
393
394 /* Add Delay */
395 delayMs(15);
396
397 /* Select DAC1 (Left) to Left Headphone Output PGA (HPOUT1LVOL) path */
398 counter += writeReg16(0x2D, 0x0001);
399
400 /* Select DAC1 (Right) to Right Headphone Output PGA (HPOUT1RVOL) path */
401 counter += writeReg16(0x2E, 0x0001);
402
403 /* Enable Left Output Mixer (MIXOUTL), Enable Right Output Mixer (MIXOUTR) */
404 /* idem for SPKOUTL and SPKOUTR */
405 counter += writeReg16(0x03, 0x0030 | 0x0300);
406
407 /* Enable DC Servo and trigger start-up mode on left and right channels */
408 counter += writeReg16(0x54, 0x0033);
409
410 /* Add Delay */
411 delayMs(257);
412
413 /* Enable HPOUT1 (Left) and HPOUT1 (Right) intermediate and output stages. Remove clamps */
414 counter += writeReg16(0x60, 0x00EE);
415
416 /* Unmutes */
417
418 /* Unmute DAC 1 (Left) */
419 counter += writeReg16(0x610, 0x00C0);
420
421 /* Unmute DAC 1 (Right) */
422 counter += writeReg16(0x611, 0x00C0);
423
424 /* Unmute the AIF1 Timeslot 0 DAC path */
425 counter += writeReg16(0x420, 0x0010);
426
427 /* Unmute DAC 2 (Left) */
428 counter += writeReg16(0x612, 0x00C0);
429
430 /* Unmute DAC 2 (Right) */
431 counter += writeReg16(0x613, 0x00C0);
432
433 /* Unmute the AIF1 Timeslot 1 DAC2 path */
434 counter += writeReg16(0x422, 0x0010);
435
436 if (output_device == OUTPUT_DEVICE_HEADPHONE) {
437 /* The write-sequencer (0x110 trigger) re-enables DAC2's AIF+analog
438 * power bits (0x05) and its Timeslot1 routing (0x604/0x605) as
439 * part of its own internal bring-up, even though only DAC1/
440 * headphone was requested here - leaving DAC2 fully powered but
441 * idle, a plausible source of audible hum via crosstalk. Force it
442 * back off now that the sequencer has finished (0x0303 matches
443 * the original headphone-only value written earlier in this
444 * function). */
445 counter += writeReg16(0x05, 0x0303);
446 counter += writeReg16(0x604, 0x0000);
447 counter += writeReg16(0x605, 0x0000);
448 }
449
450 /* Volume Control */
451 setVolume(Volume);
452 }
453
454 if (input_device > 0) /* Audio input selected */
455 {
456 if ((input_device == INPUT_DEVICE_DIGITAL_MICROPHONE_1) ||
457 (input_device == INPUT_DEVICE_DIGITAL_MICROPHONE_2)) {
458 /* Enable Microphone bias 1 generator, Enable VMID */
459 power_mgnt_reg_1 |= 0x0013;
460 counter += writeReg16(0x01, power_mgnt_reg_1);
461
462 /* ADC oversample enable */
463 counter += writeReg16(0x620, 0x0002);
464
465 /* AIF ADC2 HPF enable, HPF cut = voice mode 1 fc=127Hz at fs=8kHz */
466 counter += writeReg16(0x411, 0x3800);
467 } else if ((input_device == INPUT_DEVICE_INPUT_LINE_1) ||
468 (input_device == INPUT_DEVICE_INPUT_LINE_2)) {
469 /* Enable normal bias generator, Enable VMID */
470 power_mgnt_reg_1 |= 0x0003;
471 counter += writeReg16(0x01, power_mgnt_reg_1);
472
473 /* Disable mute on IN1L, IN1L Volume = +0dB */
474 counter += writeReg16(0x18, 0x000B);
475
476 /* Disable mute on IN1R, IN1R Volume = +0dB */
477 counter += writeReg16(0x1A, 0x000B);
478
479 /* Disable mute on IN1L_TO_MIXINL, Gain = +0dB */
480 counter += writeReg16(0x29, 0x0025);
481
482 /* Disable mute on IN1R_TO_MIXINL, Gain = +0dB */
483 counter += writeReg16(0x2A, 0x0025);
484
485 /* IN1LN_TO_IN1L, IN1LP_TO_VMID, IN1RN_TO_IN1R, IN1RP_TO_VMID */
486 counter += writeReg16(0x28, 0x0011);
487
488 /* AIF ADC1 HPF enable, HPF cut = hifi mode fc=4Hz at fs=48kHz */
489 counter += writeReg16(0x410, 0x1800);
490 }
491 /* Volume Control */
492 setVolume(Volume);
493 }
494 /* Return communication control value */
495 return counter;
496 }
497
499 void deinit() {
500 /* Deinitialize Audio Codec interface */
501 }
502
504 uint32_t readId() { return ((uint32_t)readReg16(WM8994_CHIPID_ADDR)); }
505
510 static const struct {
511 uint16_t reg;
512 const char *name;
513 } regs[] = {
514 {0x00, "SW Reset / Chip ID"},
515 {0x01, "Power Management (1)"},
516 {0x02, "Power Management (2)"},
517 {0x03, "Power Management (3)"},
518 {0x04, "Power Management (4)"},
519 {0x05, "Power Management (5)"},
520 {0x18, "Left Line Input 1&2 Volume"},
521 {0x1A, "Right Line Input 1&2 Volume"},
522 {0x1C, "Left Output Volume"},
523 {0x1D, "Right Output Volume"},
524 {0x22, "Left OPGA Volume"},
525 {0x23, "Right OPGA Volume"},
526 {0x26, "Speaker Volume Left"},
527 {0x27, "Speaker Volume Right"},
528 {0x28, "Input Mixer (2)"},
529 {0x29, "Input Mixer (3)"},
530 {0x2A, "Input Mixer (4)"},
531 {0x2D, "Output Mixer (1)"},
532 {0x2E, "Output Mixer (2)"},
533 {0x36, "Output Mixer (5)"},
534 {0x39, "Antipop (1)"},
535 {0x51, "Class W (1)"},
536 {0x54, "DC Servo (1)"},
537 {0x60, "Analogue HP (1)"},
538 {0x4C, "Charge Pump (1)"},
539 {0x102, "Clocking (1) - errata"},
540 {0x110, "Write Sequencer Ctrl (1)"},
541 {0x200, "AIF1 Clocking (1)"},
542 {0x208, "Clocking (1)"},
543 {0x210, "AIF1 Rate"},
544 {0x300, "AIF1 Control (1)"},
545 {0x302, "AIF1 Master/Slave"},
546 {0x410, "AIF1 ADC1 Filters"},
547 {0x411, "AIF1 ADC2 Filters"},
548 {0x420, "AIF1 DAC1 Filters (1)"},
549 {0x422, "AIF1 DAC2 Filters (1)"},
550 {0x440, "AIF1 DRC1 (1)"},
551 {0x450, "AIF1 DRC2 (1)"},
552 {0x601, "AIF1 DAC1 Left Mixer Routing"},
553 {0x602, "AIF1 DAC1 Right Mixer Routing"},
554 {0x604, "AIF1 DAC2 Left Mixer Routing"},
555 {0x605, "AIF1 DAC2 Right Mixer Routing"},
556 {0x606, "DAC1 Left Mixer Routing"},
557 {0x607, "DAC1 Right Mixer Routing"},
558 {0x608, "DAC2 Left Mixer Routing"},
559 {0x609, "DAC2 Right Mixer Routing"},
560 {0x610, "DAC1 Left Volume"},
561 {0x611, "DAC1 Right Volume"},
562 {0x612, "DAC2 Left Volume"},
563 {0x613, "DAC2 Right Volume"},
564 {0x620, "Oversampling"},
565 {0x700, "GPIO 1"},
566 {0x817, "Clocking - errata"},
567 };
568 AD_LOGI("WM8994 register dump (%d registers):",
569 (int)(sizeof(regs) / sizeof(regs[0])));
570 for (auto &r : regs) {
571 AD_LOGI(" 0x%04X %-28s = 0x%04X", r.reg, r.name, readReg16(r.reg));
572 }
573 }
574
580 uint32_t play(uint16_t *pBuffer, uint16_t Size) {
581 uint32_t counter = 0;
582
583 /* Resumes the audio file playing */
584 /* Unmute the output first */
585 counter += setMute(AUDIO_MUTE_OFF);
586
587 return counter;
588 }
589
591 uint32_t pause() {
592 uint32_t counter = 0;
593
594 /* Pause the audio file playing */
595 /* Mute the output first */
596 counter += setMute(AUDIO_MUTE_ON);
597
598 /* Put the Codec in Power save mode */
599 counter += writeReg16(0x02, 0x01);
600
601 return counter;
602 }
603
605 uint32_t resume() {
606 uint32_t counter = 0;
607
608 /* Resumes the audio file playing */
609 /* Unmute the output first */
610 counter += setMute(AUDIO_MUTE_OFF);
611
612 return counter;
613 }
614
627 uint32_t stop(uint32_t CodecPdwnMode) {
628 uint32_t counter = 0;
629
630 if (output_enabled != 0) {
631 /* Mute the output first */
632 counter += setMute(AUDIO_MUTE_ON);
633
634 if (CodecPdwnMode == CODEC_PDWN_SW) {
635 /* Only output mute required*/
636 } else /* CODEC_PDWN_HW */
637 {
638 /* Mute the AIF1 Timeslot 0 DAC1 path */
639 counter += writeReg16(0x420, 0x0200);
640
641 /* Mute the AIF1 Timeslot 1 DAC2 path */
642 counter += writeReg16(0x422, 0x0200);
643
644 /* Disable DAC1L_TO_HPOUT1L */
645 counter += writeReg16(0x2D, 0x0000);
646
647 /* Disable DAC1R_TO_HPOUT1R */
648 counter += writeReg16(0x2E, 0x0000);
649
650 /* Disable DAC1 and DAC2 */
651 counter += writeReg16(0x05, 0x0000);
652
653 /* Reset Codec by writing in 0x0000 address register */
654 counter += writeReg16(0x0000, 0x0000);
655
656 output_enabled = 0;
657 }
658 }
659 return counter;
660 }
661
668 uint32_t setVolume(uint8_t Volume) {
669 uint32_t counter = 0;
670 uint8_t convertedvol = wm8994VolumeConvert(Volume);
671 AD_LOGD("setVolume: Volume=%d convertedvol=0x%X output_enabled=%d", Volume,
672 convertedvol, output_enabled);
673
674 /* Output volume */
675 if (output_enabled != 0) {
676 if (convertedvol > 0x3E) {
677 /* Unmute audio codec */
678 counter += setMute(AUDIO_MUTE_OFF);
679
680 /* Left Headphone Volume (0x100 = HPOUT1_VU, a self-clearing
681 * "apply now" strobe) */
682 counter += writeReg16(0x1C, 0x3F | 0x140);
683
684 /* Right Headphone Volume */
685 counter += writeReg16(0x1D, 0x3F | 0x140);
686
687 /* Left Speaker Volume */
688 counter += writeReg16(0x26, 0x3F | 0x140);
689
690 /* Right Speaker Volume */
691 counter += writeReg16(0x27, 0x3F | 0x140);
692 } else if (Volume == 0) {
693 /* Mute audio codec */
694 counter += setMute(AUDIO_MUTE_ON);
695 } else {
696 /* Unmute audio codec */
697 counter += setMute(AUDIO_MUTE_OFF);
698
699 /* Left Headphone Volume (0x100 = HPOUT1_VU, self-clearing strobe) */
700 counter += writeReg16(0x1C, convertedvol | 0x140);
701
702 /* Right Headphone Volume */
703 counter += writeReg16(0x1D, convertedvol | 0x140);
704
705 /* Left Speaker Volume */
706 counter += writeReg16(0x26, convertedvol | 0x140);
707
708 /* Right Speaker Volume */
709 counter += writeReg16(0x27, convertedvol | 0x140);
710 }
711 }
712
713 /* Input volume */
714 if (input_enabled != 0) {
715 convertedvol = volumeInConvert(Volume);
716
717 /* Left AIF1 ADC1 volume */
718 counter += writeReg16(0x400, convertedvol | 0x100);
719
720 /* Right AIF1 ADC1 volume */
721 counter += writeReg16(0x401, convertedvol | 0x100);
722
723 /* Left AIF1 ADC2 volume */
724 counter += writeReg16(0x404, convertedvol | 0x100);
725
726 /* Right AIF1 ADC2 volume */
727 counter += writeReg16(0x405, convertedvol | 0x100);
728 }
729 return counter;
730 }
731
738 uint32_t setMute(uint32_t Cmd) {
739 uint32_t counter = 0;
740
741 if (output_enabled != 0) {
742 /* Set the Mute mode */
743 if (Cmd == AUDIO_MUTE_ON) {
744 /* Soft Mute the AIF1 Timeslot 0 DAC1 path L&R */
745 counter += writeReg16(0x420, 0x0200);
746
747 /* Soft Mute the AIF1 Timeslot 1 DAC2 path L&R */
748 counter += writeReg16(0x422, 0x0200);
749 } else /* AUDIO_MUTE_OFF Disable the Mute */
750 {
751 /* Unmute the AIF1 Timeslot 0 DAC1 path L&R */
752 counter += writeReg16(0x420, 0x0000);
753
754 /* Unmute the AIF1 Timeslot 1 DAC2 path L&R */
755 counter += writeReg16(0x422, 0x0000);
756 }
757 }
758 return counter;
759 }
760
768 uint32_t setOutputMode(uint8_t Output) {
769 uint32_t counter = 0;
770
771 switch (Output) {
773 /* Enable DAC1 (Left), Enable DAC1 (Right),
774 Disable DAC2 (Left), Disable DAC2 (Right)*/
775 counter += writeReg16(0x05, 0x0C0C);
776
777 /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */
778 counter += writeReg16(0x601, 0x0000);
779
780 /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */
781 counter += writeReg16(0x602, 0x0000);
782
783 /* Disable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */
784 counter += writeReg16(0x604, 0x0002);
785
786 /* Disable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */
787 counter += writeReg16(0x605, 0x0002);
788 break;
789
791 /* Disable DAC1 (Left), Disable DAC1 (Right),
792 Enable DAC2 (Left), Enable DAC2 (Right)*/
793 counter += writeReg16(0x05, 0x0303);
794
795 /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */
796 counter += writeReg16(0x601, 0x0001);
797
798 /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */
799 counter += writeReg16(0x602, 0x0001);
800
801 /* Disable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */
802 counter += writeReg16(0x604, 0x0000);
803
804 /* Disable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */
805 counter += writeReg16(0x605, 0x0000);
806 break;
807
809 /* Enable DAC1 (Left), Enable DAC1 (Right),
810 also Enable DAC2 (Left), Enable DAC2 (Right)*/
811 counter += writeReg16(0x05, 0x0303 | 0x0C0C);
812
813 /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */
814 counter += writeReg16(0x601, 0x0001);
815
816 /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */
817 counter += writeReg16(0x602, 0x0001);
818
819 /* Enable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */
820 counter += writeReg16(0x604, 0x0002);
821
822 /* Enable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */
823 counter += writeReg16(0x605, 0x0002);
824 break;
825
826 default:
827 /* Disable DAC1 (Left), Disable DAC1 (Right),
828 Enable DAC2 (Left), Enable DAC2 (Right)*/
829 counter += writeReg16(0x05, 0x0303);
830
831 /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */
832 counter += writeReg16(0x601, 0x0001);
833
834 /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */
835 counter += writeReg16(0x602, 0x0001);
836
837 /* Disable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */
838 counter += writeReg16(0x604, 0x0000);
839
840 /* Disable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */
841 counter += writeReg16(0x605, 0x0000);
842 break;
843 }
844 return counter;
845 }
846
852 uint32_t setFrequency(uint32_t AudioFreq) {
853 uint32_t counter = 0;
854
855 /* Clock Configurations */
856 switch (AudioFreq) {
858 /* AIF1 Sample Rate = 8 (KHz), ratio=256 */
859 counter += writeReg16(0x210, 0x0003);
860 break;
861
863 /* AIF1 Sample Rate = 16 (KHz), ratio=256 */
864 counter += writeReg16(0x210, 0x0033);
865 break;
866
868 /* AIF1 Sample Rate = 48 (KHz), ratio=256 */
869 counter += writeReg16(0x210, 0x0083);
870 break;
871
873 /* AIF1 Sample Rate = 96 (KHz), ratio=256 */
874 counter += writeReg16(0x210, 0x00A3);
875 break;
876
878 /* AIF1 Sample Rate = 11.025 (KHz), ratio=256 */
879 counter += writeReg16(0x210, 0x0013);
880 break;
881
883 /* AIF1 Sample Rate = 22.050 (KHz), ratio=256 */
884 counter += writeReg16(0x210, 0x0043);
885 break;
886
888 /* AIF1 Sample Rate = 44.1 (KHz), ratio=256 */
889 counter += writeReg16(0x210, 0x0073);
890 break;
891
892 default:
893 /* AIF1 Sample Rate = 48 (KHz), ratio=256 */
894 counter += writeReg16(0x210, 0x0083);
895 break;
896 }
897 return counter;
898 }
899
901 uint32_t reset() {
902 uint32_t counter = 0;
903
904 /* Reset Codec by writing in 0x0000 address register */
905 counter = writeReg16(0x0000, 0x0000);
906 output_enabled = 0;
907 input_enabled = 0;
908
909 return counter;
910 }
917 void writeReg(uint16_t reg, uint16_t value) {
918 uint8_t reg_be[2] = {(uint8_t)(reg >> 8), (uint8_t)(reg & 0xFF)};
919 uint8_t value_be[2] = {(uint8_t)(value >> 8), (uint8_t)(value & 0xFF)};
920 i2c_bus_write_bytes(i2c_handle, i2c_addr, reg_be, sizeof(reg_be), value_be,
921 sizeof(value_be));
922 }
923
925 uint16_t readReg16(uint16_t reg) {
926 uint8_t reg_be[2] = {(uint8_t)(reg >> 8), (uint8_t)(reg & 0xFF)};
927 uint8_t value_be[2] = {0, 0};
928 i2c_bus_read_bytes(i2c_handle, i2c_addr, reg_be, sizeof(reg_be), value_be,
929 sizeof(value_be));
930 return ((uint16_t)value_be[0] << 8) | value_be[1];
931 }
932
939 uint8_t writeReg16(uint16_t Reg, uint16_t Value) {
940 uint32_t result = 0;
941
942 writeReg(Reg, Value);
943
944#ifdef VERIFY_WRITTENDATA
945 /* Verify that the data has been correctly written */
946 result = (readReg16(Reg) == Value) ? 0 : 1;
947#endif /* VERIFY_WRITTENDATA */
948
949 return result;
950 }
951
970 uint8_t writeReg16Verified(uint16_t reg, uint16_t value,
971 uint16_t mask = 0xFFFF, uint8_t maxRetries = 20,
972 uint32_t retryDelayMs = 25) {
973 for (uint8_t attempt = 0; attempt < maxRetries; attempt++) {
974 writeReg(reg, value);
975 if ((readReg16(reg) & mask) == (value & mask)) {
976 if (attempt > 0) {
977 AD_LOGD("writeReg16Verified: reg=0x%X stuck after %d retries", reg,
978 attempt);
979 }
980 return 0;
981 }
982 delayMs(retryDelayMs);
983 }
984 AD_LOGE(
985 "writeReg16Verified: reg=0x%X never retained 0x%X after %d retries",
986 reg, value, maxRetries);
987 return 1;
988 }
989
990 static constexpr uint8_t wm8994VolumeConvert(uint8_t volume) {
991 return volume > 100 ? 100 : (uint8_t)((volume * 63) / 100);
992 }
993 static constexpr uint8_t volumeInConvert(uint8_t volume) {
994 return volume >= 100 ? 239 : (uint8_t)((volume * 240) / 100);
995 }
996
997 protected:
1000 uint32_t output_enabled = 0;
1001 uint32_t input_enabled = 0;
1004 bool is_cold_startup = true;
1005};
1006
1007} // namespace audio_driver
1008
1021/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
#define AD_LOGD(...)
Definition Logger.h:12
#define AD_LOGI(...)
Definition Logger.h:13
#define AD_LOGE(...)
Definition Logger.h:15
Header-only driver class for the WM8994 audio codec chip.
Definition WM8994.h:61
static constexpr uint16_t INPUT_DEVICE_INPUT_LINE_2
Definition WM8994.h:81
static constexpr uint8_t wm8994VolumeConvert(uint8_t volume)
Definition WM8994.h:990
uint16_t readReg16(uint16_t reg)
Reads back a register value over I2C (see writeReg's note on byte order)
Definition WM8994.h:925
static constexpr uint16_t OUTPUT_DEVICE_HEADPHONE
Definition WM8994.h:75
static constexpr int CODEC_PDWN_HW
Definition WM8994.h:87
AudioFrequency
Definition WM8994.h:63
@ AUDIO_FREQUENCY_22K
Definition WM8994.h:69
@ AUDIO_FREQUENCY_32K
Definition WM8994.h:68
@ AUDIO_FREQUENCY_96K
Definition WM8994.h:65
@ AUDIO_FREQUENCY_44K
Definition WM8994.h:67
@ AUDIO_FREQUENCY_16K
Definition WM8994.h:70
@ AUDIO_FREQUENCY_8K
Definition WM8994.h:72
@ AUDIO_FREQUENCY_192K
Definition WM8994.h:64
@ AUDIO_FREQUENCY_11K
Definition WM8994.h:71
@ AUDIO_FREQUENCY_48K
Definition WM8994.h:66
uint32_t init(uint16_t OutputInputDevice, uint8_t Volume, uint32_t AudioFreq)
Initializes the audio codec and the control interface.
Definition WM8994.h:115
uint8_t writeReg16(uint16_t Reg, uint16_t Value)
Writes a single data value to a codec register.
Definition WM8994.h:939
uint32_t output_enabled
Definition WM8994.h:1000
void setAddress(int addr)
Defines the I2C device address.
Definition WM8994.h:101
static constexpr uint16_t OUTPUT_DEVICE_BOTH
Definition WM8994.h:76
uint32_t setFrequency(uint32_t AudioFreq)
Sets new frequency.
Definition WM8994.h:852
uint32_t setOutputMode(uint8_t Output)
Switch dynamically (while audio file is played) the output target (speaker or headphone).
Definition WM8994.h:768
uint32_t readId()
Get the WM8994 ID.
Definition WM8994.h:504
uint32_t resume()
Resumes playing on the audio codec.
Definition WM8994.h:605
int i2c_addr
Definition WM8994.h:999
static constexpr uint8_t DEFAULT_VOLMIN
Definition WM8994.h:82
bool is_cold_startup
Definition WM8994.h:1004
static constexpr uint8_t DEFAULT_VOLSTEP
Definition WM8994.h:84
static constexpr uint16_t INPUT_DEVICE_DIGITAL_MICROPHONE_2
Definition WM8994.h:79
static constexpr uint16_t INPUT_DEVICE_INPUT_LINE_1
Definition WM8994.h:80
uint32_t setVolume(uint8_t Volume)
Sets higher or lower the codec volume level.
Definition WM8994.h:668
uint32_t pause()
Pauses playing on the audio codec.
Definition WM8994.h:591
static constexpr uint16_t INPUT_DEVICE_DIGITAL_MICROPHONE_1
Definition WM8994.h:78
void setWire(i2c_bus_handle_t handle)
Defines the I2C bus instance to be used.
Definition WM8994.h:98
static constexpr uint16_t OUTPUT_DEVICE_SPEAKER
Definition WM8994.h:74
static constexpr uint8_t volumeInConvert(uint8_t volume)
Definition WM8994.h:993
static constexpr int AUDIO_MUTE_ON
Definition WM8994.h:89
void deinit()
Deinitializes the audio codec.
Definition WM8994.h:499
uint8_t writeReg16Verified(uint16_t reg, uint16_t value, uint16_t mask=0xFFFF, uint8_t maxRetries=20, uint32_t retryDelayMs=25)
Writes a register and confirms (by reading it back) that the value actually stuck,...
Definition WM8994.h:970
static constexpr uint16_t OUTPUT_DEVICE_AUTO
Definition WM8994.h:77
void dumpRegisters()
Definition WM8994.h:509
uint32_t reset()
Resets wm8994 registers.
Definition WM8994.h:901
uint32_t setMute(uint32_t Cmd)
Enables or disables the mute feature on the audio codec.
Definition WM8994.h:738
i2c_bus_handle_t i2c_handle
Definition WM8994.h:998
static constexpr int AUDIO_RESUME
Definition WM8994.h:86
static constexpr int CODEC_PDWN_SW
Definition WM8994.h:88
static constexpr int WM8994_ADDR
Definition WM8994.h:93
uint32_t play(uint16_t *pBuffer, uint16_t Size)
Start the audio Codec play feature.
Definition WM8994.h:580
static constexpr uint8_t DEFAULT_VOLMAX
Definition WM8994.h:83
uint32_t stop(uint32_t CodecPdwnMode)
Stops audio Codec playing. It powers down the codec.
Definition WM8994.h:627
void writeReg(uint16_t reg, uint16_t value)
Definition WM8994.h:917
static constexpr int AUDIO_PAUSE
Definition WM8994.h:85
uint32_t input_enabled
Definition WM8994.h:1001
static constexpr int AUDIO_MUTE_OFF
Definition WM8994.h:90
static constexpr uint32_t WM8994_ID
Definition WM8994.h:91
static constexpr uint16_t WM8994_CHIPID_ADDR
Definition WM8994.h:92
Namespace for audio driver components.
Definition AudioBoard.h:5
void delayMs(unsigned long ms)
Definition API_Delay.h:19
void * i2c_bus_handle_t
Definition DriverCommon.h:155