use core::marker::PhantomData;
use embassy_hal_internal::{Peri, PeripheralType};
use embassy_time::{Duration, block_for};
use crate::{
gpio::{Basic, Flex, Pin},
module_stop::ModuleStop,
pac::dac12::vals::Ref,
};
#[allow(private_bounds)]
pub struct Dac<'d, I: Instance> {
_output_pin: Flex<'d, Basic>,
_phantom: PhantomData<&'d I>,
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Copy, Clone, Default, Debug)]
pub enum Align {
Left,
#[default]
Right,
}
pub enum Vref {
AnalogReference,
AnalogSupply,
Internal,
None,
}
#[allow(private_bounds)]
pub trait DacOutputPin: SealedDacOutputPin {}
pub(crate) trait SealedDacOutputPin: Pin + PeripheralType {}
#[allow(private_bounds)]
pub trait Instance: SealedInstance + ModuleStop + PeripheralType {}
pub(crate) trait SealedInstance: PeripheralType {
fn regs() -> crate::pac::dac12::Dac12;
}
impl<'d, I: Instance> Dac<'d, I> {
pub fn new<P: DacOutputPin>(peri: Peri<'d, I>, output_pin: Peri<'d, P>) -> Self {
let _ = peri;
I::start_module();
output_pin.set_as_analog();
let mut this = Self {
_output_pin: Flex::new(output_pin),
_phantom: PhantomData,
};
this.set_vref(Vref::AnalogSupply);
this
}
#[inline(always)]
pub fn buffer(&self) -> *mut u16 {
let dac = I::regs();
dac.dadr0().as_ptr()
}
#[inline(always)]
pub fn set_align(&mut self, align: Align) {
let dac = I::regs();
match align {
Align::Left => dac.dadpr().modify(|r| r.set_dpsel(true)),
Align::Right => dac.dadpr().modify(|r| r.set_dpsel(false)),
}
}
#[inline(always)]
pub fn set_vref(&mut self, vref: Vref) {
let dac = I::regs();
dac.davrefcr().modify(|r| r.set_ref_(Ref::None));
dac.dadr0().write_value(0);
dac.dacr().modify(|r| r.set_daoe0(false));
block_for(Duration::from_micros(10));
let vref = match vref {
Vref::AnalogReference => Ref::Vref,
Vref::AnalogSupply => Ref::Avcc0,
Vref::Internal => Ref::Internal,
Vref::None => return,
};
dac.davrefcr().modify(|r| r.set_ref_(vref));
dac.dacr().modify(|r| r.set_daoe0(true));
block_for(Duration::from_micros(5));
}
#[inline(always)]
pub fn set(&mut self, value: u16) {
trace!("Set {}", value);
let dac = I::regs();
dac.dadr0().write_value(value);
}
#[inline(always)]
pub fn start(&mut self) {
let dac = I::regs();
dac.dacr().write(|w| w.set_daoe0(true));
}
#[inline(always)]
pub fn stop(&mut self) {
let dac = I::regs();
dac.dacr().write(|w| w.set_daoe0(false));
}
}
impl<'d, I: Instance> Drop for Dac<'d, I> {
fn drop(&mut self) {
warn!("DAC12: Drop");
let dac = I::regs();
dac.dacr().modify(|r| r.set_daoe0(false));
I::stop_module();
}
}
impl Instance for crate::peripherals::DAC12_0 {}
impl SealedInstance for crate::peripherals::DAC12_0 {
#[inline(always)]
fn regs() -> crate::pac::dac12::Dac12 {
crate::pac::DAC12_0
}
}
macro_rules! dac_pin {
($pin:ident) => {
impl crate::dac::DacOutputPin for crate::peripherals::$pin {}
impl crate::dac::SealedDacOutputPin for crate::peripherals::$pin {}
};
}
pub(crate) use dac_pin;