use core::ops::Deref;
use vorago_shared_hal::{
PeripheralSelect, disable_peripheral_clock, enable_peripheral_clock,
reset_peripheral_for_cycles,
};
use crate::{clock::Clocks, pac};
pub type DacRegisterBlock = pac::dac0::RegisterBlock;
pub trait DacInstance: Deref<Target = DacRegisterBlock> {
const IDX: u8;
fn ptr() -> *const DacRegisterBlock;
}
impl DacInstance for pac::Dac0 {
const IDX: u8 = 0;
#[inline(always)]
fn ptr() -> *const DacRegisterBlock {
Self::ptr()
}
}
impl DacInstance for pac::Dac1 {
const IDX: u8 = 1;
#[inline(always)]
fn ptr() -> *const DacRegisterBlock {
Self::ptr()
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum DacSettling {
NoSettling = 0,
Apb2Times25 = 1,
Apb2Times50 = 2,
Apb2Times75 = 3,
Apb2Times100 = 4,
Apb2Times125 = 5,
Apb2Times150 = 6,
}
pub struct Dac(*const DacRegisterBlock);
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ValueTooLarge;
impl Dac {
pub fn new<Dac: DacInstance>(dac: Dac, dac_settling: DacSettling, _clocks: &Clocks) -> Self {
enable_peripheral_clock(PeripheralSelect::Dac);
dac.ctrl1().write(|w| {
w.dac_en().set_bit();
unsafe { w.dac_settling().bits(dac_settling as u8) }
});
let mut dac = Self(Dac::ptr());
dac.clear_fifo();
dac.clear_irqs();
dac
}
pub const fn regs(&self) -> &DacRegisterBlock {
unsafe { &*self.0 }
}
#[inline(always)]
pub fn clear_irqs(&mut self) {
self.regs().irq_clr().write(|w| {
w.fifo_oflow().set_bit();
w.fifo_uflow().set_bit();
w.dac_done().set_bit();
w.trig_error().set_bit()
});
}
#[inline(always)]
pub fn clear_fifo(&mut self) {
self.regs().fifo_clr().write(|w| unsafe { w.bits(1) });
}
#[inline(always)]
pub fn load_value(&mut self, val: u16) -> nb::Result<(), ValueTooLarge> {
if val > 2_u16.pow(12) - 1 {
return Err(nb::Error::Other(ValueTooLarge));
}
let regs = self.regs();
if regs.status().read().fifo_entry_cnt().bits() >= 32_u8 {
return Err(nb::Error::WouldBlock);
}
regs.fifo_data().write(|w| unsafe { w.bits(val.into()) });
Ok(())
}
#[inline(always)]
pub fn load_and_trigger_manually(&mut self, val: u16) -> Result<(), ValueTooLarge> {
if val > 2_u16.pow(12) - 1 {
return Err(ValueTooLarge);
}
self.clear_fifo();
nb::block!(self.load_value(val)).unwrap();
self.trigger_manually();
Ok(())
}
#[inline(always)]
pub fn trigger_manually(&self) {
self.regs().ctrl0().write(|w| w.man_trig_en().set_bit());
}
#[inline(always)]
pub fn enable_external_trigger(&self) {
self.regs().ctrl0().write(|w| w.ext_trig_en().set_bit());
}
pub fn is_settled(&self) -> nb::Result<(), ()> {
if self.regs().status().read().dac_busy().bit_is_set() {
return Err(nb::Error::WouldBlock);
}
Ok(())
}
#[inline(always)]
pub fn reset(&mut self) {
enable_peripheral_clock(PeripheralSelect::Dac);
reset_peripheral_for_cycles(PeripheralSelect::Dac, 2);
}
#[inline(always)]
pub fn stop(self) {
disable_peripheral_clock(PeripheralSelect::Dac);
}
}