use super::hal::{
gpio::{self, gpioc},
hal::blocking::spi::Write,
prelude::*,
rcc, spi, stm32,
time::MegaHertz,
};
use super::OutputChannelIdx;
use defmt::Format;
const SPI_CLOCK: MegaHertz = MegaHertz::MHz(8);
pub const R_SENSE: f32 = 0.05; pub const VREF_TEC: f32 = 1.5;
#[derive(Debug)]
pub enum Error {
Bounds,
}
#[derive(Copy, Clone, Debug, Format)]
pub struct DacCode(u32);
impl DacCode {
const MAX_DAC_WORD: i32 = 1 << 20; const VREF_DAC: f32 = 3.0; pub const MAX_CURRENT: f32 = (((DacCode::MAX_DAC_WORD - 1) as f32 * DacCode::VREF_DAC
/ DacCode::MAX_DAC_WORD as f32)
- VREF_TEC)
/ (10.0 * R_SENSE);
}
impl TryFrom<f32> for DacCode {
type Error = Error;
fn try_from(current: f32) -> Result<DacCode, Error> {
let ctli_voltage = current * (10.0 * R_SENSE) + VREF_TEC;
let dac_code = (ctli_voltage * (DacCode::MAX_DAC_WORD as f32 / DacCode::VREF_DAC)) as i32;
if !(0..DacCode::MAX_DAC_WORD).contains(&dac_code) {
return Err(Error::Bounds);
};
Ok(Self(dac_code as u32))
}
}
impl From<DacCode> for u32 {
fn from(code: DacCode) -> u32 {
code.0
}
}
pub struct DacPins {
pub sync: [gpio::ErasedPin<gpio::Output>; 4],
}
pub struct Dac {
spi: spi::Spi<stm32::SPI3, spi::Enabled, u8>,
pins: DacPins,
}
impl Dac {
pub fn new(
clocks: &rcc::CoreClocks,
spi3_rec: rcc::rec::Spi3,
spi3: stm32::SPI3,
sck: gpioc::PC10<gpio::Alternate<6>>,
mosi: gpioc::PC12<gpio::Alternate<6>>,
pins: DacPins,
) -> Self {
let spi = spi3.spi(
(sck, spi::NoMiso, mosi),
spi::MODE_1,
SPI_CLOCK.convert(),
spi3_rec,
clocks,
);
let mut dac = Dac { spi, pins };
for pin in dac.pins.sync.iter_mut() {
pin.set_high();
}
for i in 0..4 {
let ch = OutputChannelIdx::try_from(i).unwrap();
dac.set(ch, (0.0).try_into().unwrap());
}
dac
}
pub fn set(&mut self, ch: OutputChannelIdx, dac_code: DacCode) {
self.pins.sync[ch as usize].set_low();
let buf = u32::from(dac_code).to_be_bytes();
self.spi.write(&buf[1..]).unwrap();
self.pins.sync[ch as usize].set_high();
}
}