74 lines
1.9 KiB
Rust
74 lines
1.9 KiB
Rust
use cortex_m::prelude::{_embedded_hal_blocking_i2c_Write, _embedded_hal_blocking_i2c_WriteRead};
|
|
|
|
use crate::CodecPins;
|
|
use crate::hal::prelude::*;
|
|
use crate::traits::Dac;
|
|
|
|
const CS4398_I2C_ADDRESS: u8 = 0x4f;
|
|
|
|
#[repr(u8)]
|
|
#[allow(dead_code)]
|
|
enum RegisterAddress {
|
|
ChipId = 0x01,
|
|
ModeControl = 0x02,
|
|
VolMixInvControl = 0x03,
|
|
MuteControl = 0x04,
|
|
ChAVol = 0x05,
|
|
ChBVol = 0x06,
|
|
RampFiltControl = 0x07,
|
|
MiscControl = 0x08,
|
|
MiscControl2 = 0x09,
|
|
}
|
|
|
|
pub struct Cs4398Dac<T> {
|
|
i2c: T,
|
|
pins: CodecPins,
|
|
}
|
|
|
|
impl<T> Cs4398Dac<T>
|
|
where
|
|
T: _embedded_hal_blocking_i2c_WriteRead + _embedded_hal_blocking_i2c_Write,
|
|
{
|
|
#[inline]
|
|
fn write_reg(&mut self, reg: RegisterAddress, val: u8) {
|
|
self.i2c.write(CS4398_I2C_ADDRESS, &[reg as u8, val]).ok();
|
|
}
|
|
fn fm_for_rate(&self, rate: u32) -> u8 {
|
|
match rate {
|
|
r if r <= 50000 => 0b00,
|
|
r if r <= 100000 => 0b01,
|
|
_ => 0b10,
|
|
// DSD mode 0b11 is not used
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T> Dac<T> for Cs4398Dac<T>
|
|
where
|
|
T: _embedded_hal_blocking_i2c_WriteRead + _embedded_hal_blocking_i2c_Write,
|
|
{
|
|
fn new(i2c: T, pins: CodecPins) -> Self {
|
|
Cs4398Dac { i2c, pins }
|
|
}
|
|
fn init(&mut self) {
|
|
// reset
|
|
self.pins.reset.set_low().ok();
|
|
self.pins.reset.set_high().ok();
|
|
// power up, enable control port
|
|
self.write_reg(RegisterAddress::MiscControl, 1 << 6);
|
|
self.mute();
|
|
// set audio protocol to I2S, Single rate mode
|
|
self.write_reg(RegisterAddress::ModeControl, 1 << 4);
|
|
}
|
|
fn change_rate(&mut self, new_rate: u32) {
|
|
let mode_control = (1 << 4) | self.fm_for_rate(new_rate);
|
|
self.write_reg(RegisterAddress::ModeControl, mode_control);
|
|
}
|
|
fn mute(&mut self) {
|
|
self.write_reg(RegisterAddress::MuteControl, 0xc0 | (0b11 << 3));
|
|
}
|
|
fn unmute(&mut self) {
|
|
self.write_reg(RegisterAddress::MuteControl, 0xc0);
|
|
}
|
|
}
|