workspace with shared hid shape for cli
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
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 AK4490_I2C_ADDRESS: u8 = 0x10;
|
||||
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
enum RegisterAddress {
|
||||
Control1 = 0x00,
|
||||
Control2 = 0x01,
|
||||
Control3 = 0x02,
|
||||
LeftAtt = 0x03,
|
||||
RightAtt = 0x04,
|
||||
Control4 = 0x05,
|
||||
Control5 = 0x06,
|
||||
Control6 = 0x07,
|
||||
Control7 = 0x08,
|
||||
Control8 = 0x09,
|
||||
}
|
||||
|
||||
pub struct Ak4490Dac<T> {
|
||||
i2c: T,
|
||||
pins: CodecPins, // this dependency is unfortunate, but non trivial to generalize
|
||||
}
|
||||
|
||||
impl<T> Ak4490Dac<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(AK4490_I2C_ADDRESS, &[reg as u8, val]).ok();
|
||||
}
|
||||
fn dfs_for_rate(&self, rate: u32) -> u8 {
|
||||
match rate {
|
||||
r if r < 54000 => 0,
|
||||
r if r < 108000 => 1,
|
||||
r if r < 216000 => 2,
|
||||
r if r <= 384000 => 4,
|
||||
_ => 5,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Dac<T> for Ak4490Dac<T>
|
||||
where
|
||||
T: _embedded_hal_blocking_i2c_WriteRead + _embedded_hal_blocking_i2c_Write,
|
||||
{
|
||||
fn new(i2c: T, pins: CodecPins) -> Self {
|
||||
Self { i2c, pins }
|
||||
}
|
||||
fn init(&mut self) {
|
||||
// bring out of reset
|
||||
self.pins.reset.set_high();
|
||||
self.write_reg(RegisterAddress::Control1, (1 << 7) | 0x0e | (1 << 0)); // ACKS | I2S-32 | RSTN
|
||||
let dfs = 0; // start in 48k mode, change_rate will be called after init
|
||||
self.write_reg(RegisterAddress::Control2, 0x22 | ((dfs & 0x3) << 3));
|
||||
self.write_reg(RegisterAddress::Control4, (dfs & 0x4) >> 1);
|
||||
}
|
||||
fn change_rate(&mut self, new_rate: u32) {
|
||||
let dfs = self.dfs_for_rate(new_rate);
|
||||
self.write_reg(RegisterAddress::Control2, 0x22 | ((dfs & 0x3) << 3));
|
||||
self.write_reg(RegisterAddress::Control4, (dfs & 0x4) >> 1);
|
||||
}
|
||||
fn set_volume(&mut self, left: u8, right: u8) {
|
||||
self.write_reg(RegisterAddress::LeftAtt, left);
|
||||
self.write_reg(RegisterAddress::RightAtt, right);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use crate::traits::Dac;
|
||||
|
||||
/// Noop DAC for debugging on the EVK without a DAC connected
|
||||
pub struct NoopDac<T> {
|
||||
__: PhantomData<T>,
|
||||
}
|
||||
impl<T> Dac<T> for NoopDac<T> {
|
||||
fn init(&mut self) {}
|
||||
fn change_rate(&mut self, _new_rate: u32) {}
|
||||
fn mute(&mut self) {}
|
||||
fn new(_i2c: T, _pins: crate::CodecPins) -> Self {
|
||||
Self { __: PhantomData }
|
||||
}
|
||||
fn set_volume(&mut self, _left: u8, _right: u8) {}
|
||||
fn unmute(&mut self) {}
|
||||
}
|
||||
Reference in New Issue
Block a user