Merge branch 'evk'

This commit is contained in:
2026-05-19 21:52:28 -07:00
5 changed files with 372 additions and 55 deletions
+253
View File
@@ -0,0 +1,253 @@
use crate::{CodecPins, traits::Dac};
use embedded_hal::prelude::{
_embedded_hal_blocking_i2c_Write, _embedded_hal_blocking_i2c_WriteRead,
};
const WM8904_I2C_ADDRESS: u8 = 0b0011010;
const MCLK: u32 = 24576000 / 2; // assume EVK TODO: better
#[repr(u8)]
#[derive(Clone, Copy)]
#[allow(dead_code)]
enum RegisterAddress {
SwResetId = 0x00,
BiasControl0 = 0x04,
VmidControl = 0x05,
MicBiasControl0 = 0x06,
MicBiasControl1 = 0x07,
AnaAdc0 = 0x0a,
PowerMgmt0 = 0x0c,
PowerMgmt2 = 0x0e,
PowerMgmt3 = 0x0f,
PowerMgmt6 = 0x12,
ClockRates0 = 0x14,
ClockRates1 = 0x15,
ClockRates2 = 0x16,
AudioInterface0 = 0x18,
AudioInterface1 = 0x19,
AudioInterface2 = 0x1a,
AudioInterface3 = 0x1b,
DacDigiVolLeft = 0x1e,
DacDigiVolRight = 0x1f,
DacDigital0 = 0x20,
DacDigi1 = 0x21,
AdcDigiVolLeft = 0x24,
AdcDigiVolRight = 0x25,
AdcDigital0 = 0x26,
DigiMic0 = 0x27,
Drc0 = 0x28,
Drc1 = 0x29,
Drc2 = 0x2a,
Drc3 = 0x2b,
AnaLeftIn0 = 0x2c,
AnaRightIn0 = 0x2d,
AnaLeftIn1 = 0x2e,
AnaRightIn1 = 0x2f,
AnaOut1Left = 0x39,
AnaOut1Right = 0x3a,
AnaOut2Left = 0x3b,
AnaOut2Right = 0x3c,
AnaOut12Zc = 0x3d,
DcServo0 = 0x43,
DcServo1 = 0x44,
DcServo2 = 0x45,
DcServo4 = 0x47,
DcServo5 = 0x48,
DcServo6 = 0x49,
DcServo7 = 0x4a,
DcServo8 = 0x4b,
DcServo9 = 0x4c,
DcServoRb0 = 0x4d,
AnaHp0 = 0x5a,
AnaLineOut0 = 0x5e,
ChargePump0 = 0x62,
ClassW = 0x68,
WriteSeq0 = 0x6c,
WriteSeq1 = 0x6d,
WriteSeq2 = 0x6e,
WriteSeq3 = 0x6f,
WriteSeq4 = 0x70,
FllControl1 = 0x74,
FllControl2 = 0x75,
FllControl3 = 0x76,
FllControl4 = 0x77,
FllControl5 = 0x78,
GpioControl1 = 0x79,
GpioControl2 = 0x7a,
GpioControl3 = 0x7b,
GpioControl4 = 0x7c,
DigiPulls = 0x7e,
IntStatus = 0x7f,
IntStatusMask = 0x80,
IntPriority = 0x81,
IntDebounce = 0x82,
Eq1 = 0x86,
Eq2 = 0x87,
Eq3 = 0x88,
Eq4 = 0x89,
Eq5 = 0x8a,
Eq6 = 0x8b,
Eq7 = 0x8c,
Eq8 = 0x8d,
Eq9 = 0x8e,
Eq10 = 0x8f,
Eq11 = 0x90,
Eq12 = 0x91,
Eq13 = 0x92,
Eq14 = 0x93,
Eq15 = 0x94,
Eq16 = 0x95,
Eq17 = 0x96,
Eq18 = 0x97,
Eq19 = 0x98,
Eq20 = 0x99,
Eq21 = 0x9a,
Eq22 = 0x9b,
Eq23 = 0x9c,
Eq24 = 0x9d,
AdcTest0 = 0xc6,
FllNcoTest0 = 0xf7,
FllNcoTest1 = 0xf8,
}
pub struct Wm8904Dac<T> {
i2c: T,
pins: CodecPins,
mclk: u32,
}
impl<T> Wm8904Dac<T>
where
T: _embedded_hal_blocking_i2c_WriteRead + _embedded_hal_blocking_i2c_Write,
{
#[inline]
fn write_reg(&mut self, reg: RegisterAddress, val: u16) {
let b = val.to_be_bytes();
defmt::info!("i2c w [{:?}]", &[reg as u8, b[0], b[1]]);
self.i2c
.write(WM8904_I2C_ADDRESS, &[reg as u8, b[0], b[1]])
.ok();
}
fn cr1_for_rate(&self, rate: u32) -> u16 {
let fs_ratio = self.mclk / rate;
if !self.mclk.is_multiple_of(rate) {
defmt::warn!("sample rate should be a multiple of mclk");
}
let clk_sys_rate: u16 = match fs_ratio {
64 => 0,
128 => 1,
192 => 2,
256 => 3,
384 => 4,
512 => 5,
768 => 6,
1024 => 7,
1408 => 8,
1536 => 9,
_ => {
defmt::warn!("unsupport ratio {}", fs_ratio);
0
}
};
let sample_rate: u16 = match rate {
r if r < 11025 => 0, // 0-11024
r if r < 16000 => 1, // 11025 - 15999
r if r < 22050 => 2, // 16000 - 22049
r if r < 32000 => 3, // 22050 - 31999
r if r < 44100 => 4, // 32000 - 44099
_ => 5, // 44100+
};
(clk_sys_rate << 10) | sample_rate
}
fn blck_div_for_rate(&self, rate: u32) -> u16 {
let bits_per_frame = 64;
let bits_per_second = bits_per_frame * rate;
(self.mclk / bits_per_second) as u16
}
}
impl<T> Dac<T> for Wm8904Dac<T>
where
T: _embedded_hal_blocking_i2c_WriteRead + _embedded_hal_blocking_i2c_Write,
{
fn new(i2c: T, pins: CodecPins) -> Self {
Self {
i2c,
pins,
mclk: MCLK,
}
}
fn init(&mut self) {
let mut buf = [0u8; 2];
match self.i2c.write_read(WM8904_I2C_ADDRESS, &[0], &mut buf) {
Ok(_) => {
let chip_id = ((buf[0] as u16) << 8) | buf[1] as u16;
defmt::info!("Read chip ID: {:x}", chip_id)
}
Err(_) => defmt::error!("Error reading I2C"),
}
self.write_reg(RegisterAddress::ClockRates2, 0x000f); // OPCLK_ENA | CLK_SYS_ENA | CLK_DSP_ENA | TOCLK_ENA
self.write_reg(RegisterAddress::WriteSeq0, 0x0100); // write sequencer 0 ENA
self.write_reg(RegisterAddress::WriteSeq3, 0x0100); // write sequencer 3 START, INDEX=0
// wait on write sequencer
defmt::info!("[codec] waiting on write seq");
loop {
let mut buf = [0; 2];
self.i2c
.write_read(WM8904_I2C_ADDRESS, &[0x70], &mut buf)
.ok();
if buf[1] & 1 == 0 {
break;
}
}
defmt::debug!("[codec] write seq done");
self.write_reg(RegisterAddress::ClockRates0, 0);
self.write_reg(RegisterAddress::PowerMgmt0, 0); // IN PGAs disabled
self.write_reg(RegisterAddress::PowerMgmt2, 0x0003); // HPL_PGA_ENA | HPR_PGA_ENA
self.write_reg(RegisterAddress::PowerMgmt3, 0); //line outs disabled
self.write_reg(RegisterAddress::PowerMgmt6, 0x000c); // power management 6 = DACL_ENA | DACR_ENA
self.write_reg(RegisterAddress::AudioInterface0, 0x0050); // audio if 0 = AIFADCR_SRC | AIFDACR_SRC
self.write_reg(RegisterAddress::DacDigi1, 0x0040); // dac digital 1 = DAC_OSR128
self.write_reg(RegisterAddress::AnaLeftIn0, 0x0005);
self.write_reg(RegisterAddress::AnaRightIn0, 0x0005);
self.write_reg(RegisterAddress::AnaOut1Left, 0x0039); // analog out1 left = vol=0dB
self.write_reg(RegisterAddress::AnaOut1Right, 0x0039); // analog out1 right = vol=0dB
self.write_reg(RegisterAddress::AnaOut2Left, 0x0039); // analog out2 left = vol=0dB
self.write_reg(RegisterAddress::AnaOut2Right, 0x0039); // analog out2 right = vol=0dB
self.write_reg(RegisterAddress::DcServo0, 0x0003); // dc servo 0 = HPOUTL_ENA | HPOUTR_ENA
self.write_reg(RegisterAddress::AnaHp0, 0x00ff); // analog hp 0 = remove all shorts etc
self.write_reg(RegisterAddress::AnaLineOut0, 0x00ff); // analog lineout 0 = remove all shorts etc
self.write_reg(RegisterAddress::ClassW, 0x0001); // enable class w charge pump
self.write_reg(RegisterAddress::ChargePump0, 0x0001); // enable charge pump
self.write_reg(RegisterAddress::AudioInterface1, (3 << 2) | 2); // audio if 1 = i2s, 32 bit per sample
self.write_reg(RegisterAddress::ClockRates1, self.cr1_for_rate(96000)); // Set up for 48k, impl will change if needed
self.write_reg(RegisterAddress::ClockRates2, 0x000f); // clock rates 2 = CLK_SYS_ENA
self.write_reg(
RegisterAddress::AudioInterface2,
self.blck_div_for_rate(96000),
);
self.write_reg(RegisterAddress::AudioInterface3, 0); // audio interface 3 = input lrclock
self.write_reg(RegisterAddress::AnaOut12Zc, 0); // analog out12 zc = play source = dac
self.write_reg(RegisterAddress::DacDigiVolLeft, 0x01ff); // dac vol left = update left/right = 0dB
}
fn change_rate(&mut self, new_rate: u32) {
// TODO: mute, stop clocks etc.
defmt::info!("dac rate -> {}", new_rate);
self.write_reg(RegisterAddress::ClockRates1, self.cr1_for_rate(new_rate));
self.write_reg(
RegisterAddress::AudioInterface2,
self.blck_div_for_rate(new_rate),
);
}
fn mute(&mut self) {
// self.write_reg(RegisterAddress::DacDigiVolLeft, 0x0100);
}
fn unmute(&mut self) {
// TODO: restore previous volume
// self.write_reg(RegisterAddress::DacDigiVolLeft, 0x01ff);
}
}