va416xx_hal/
dac.rs

1//! Digital to Analog Converter (DAC) driver.
2//!
3//! ## Examples
4//!
5//! - [ADC and DAC example](https://github.com/us-irs/va416xx-rs/blob/main/examples/simple/examples/dac-adc.rs)
6use core::ops::Deref;
7
8use vorago_shared_hal::{
9    disable_peripheral_clock, enable_peripheral_clock, reset_peripheral_for_cycles,
10    PeripheralSelect,
11};
12
13use crate::{clock::Clocks, pac};
14
15pub type DacRegisterBlock = pac::dac0::RegisterBlock;
16
17/// Common trait implemented by all PAC peripheral access structures. The register block
18/// format is the same for all DAC blocks.
19pub trait DacInstance: Deref<Target = DacRegisterBlock> {
20    const IDX: u8;
21
22    fn ptr() -> *const DacRegisterBlock;
23}
24
25impl DacInstance for pac::Dac0 {
26    const IDX: u8 = 0;
27
28    #[inline(always)]
29    fn ptr() -> *const DacRegisterBlock {
30        Self::ptr()
31    }
32}
33
34impl DacInstance for pac::Dac1 {
35    const IDX: u8 = 1;
36
37    #[inline(always)]
38    fn ptr() -> *const DacRegisterBlock {
39        Self::ptr()
40    }
41}
42
43#[derive(Debug, PartialEq, Eq, Copy, Clone)]
44#[cfg_attr(feature = "defmt", derive(defmt::Format))]
45pub enum DacSettling {
46    NoSettling = 0,
47    Apb2Times25 = 1,
48    Apb2Times50 = 2,
49    Apb2Times75 = 3,
50    Apb2Times100 = 4,
51    Apb2Times125 = 5,
52    Apb2Times150 = 6,
53}
54
55pub struct Dac(*const DacRegisterBlock);
56
57#[derive(Debug, PartialEq, Eq, Copy, Clone)]
58#[cfg_attr(feature = "defmt", derive(defmt::Format))]
59pub struct ValueTooLarge;
60
61impl Dac {
62    /// Create a new [Dac] driver instance.
63    ///
64    /// The [Clocks] structure is expected here as well to ensure the clock was set up properly.
65    pub fn new<Dac: DacInstance>(dac: Dac, dac_settling: DacSettling, _clocks: &Clocks) -> Self {
66        enable_peripheral_clock(PeripheralSelect::Dac);
67
68        dac.ctrl1().write(|w| {
69            w.dac_en().set_bit();
70            // SAFETY: Enum values are valid values only.
71            unsafe { w.dac_settling().bits(dac_settling as u8) }
72        });
73        let mut dac = Self(Dac::ptr());
74        dac.clear_fifo();
75        dac.clear_irqs();
76        dac
77    }
78
79    pub const fn regs(&self) -> &DacRegisterBlock {
80        unsafe { &*self.0 }
81    }
82
83    #[inline(always)]
84    pub fn clear_irqs(&mut self) {
85        self.regs().irq_clr().write(|w| {
86            w.fifo_oflow().set_bit();
87            w.fifo_uflow().set_bit();
88            w.dac_done().set_bit();
89            w.trig_error().set_bit()
90        });
91    }
92
93    #[inline(always)]
94    pub fn clear_fifo(&mut self) {
95        self.regs().fifo_clr().write(|w| unsafe { w.bits(1) });
96    }
97
98    /// Load next value into the FIFO.
99    ///
100    /// Uses the [nb] API to allow blocking and non-blocking usage.
101    #[inline(always)]
102    pub fn load_value(&mut self, val: u16) -> nb::Result<(), ValueTooLarge> {
103        if val > 2_u16.pow(12) - 1 {
104            return Err(nb::Error::Other(ValueTooLarge));
105        }
106        let regs = self.regs();
107        if regs.status().read().fifo_entry_cnt().bits() >= 32_u8 {
108            return Err(nb::Error::WouldBlock);
109        }
110        regs.fifo_data().write(|w| unsafe { w.bits(val.into()) });
111        Ok(())
112    }
113
114    /// This loads and triggers the next value immediately. It also clears the FIFO before
115    /// loading the passed value.
116    #[inline(always)]
117    pub fn load_and_trigger_manually(&mut self, val: u16) -> Result<(), ValueTooLarge> {
118        if val > 2_u16.pow(12) - 1 {
119            return Err(ValueTooLarge);
120        }
121        self.clear_fifo();
122        // This should never block, the FIFO was cleared. We checked the value as well, so unwrap
123        // is okay here.
124        nb::block!(self.load_value(val)).unwrap();
125        self.trigger_manually();
126        Ok(())
127    }
128
129    /// Manually trigger the DAC. This will de-queue the next value inside the FIFO
130    /// to be processed by the DAC.
131    #[inline(always)]
132    pub fn trigger_manually(&self) {
133        self.regs().ctrl0().write(|w| w.man_trig_en().set_bit());
134    }
135
136    #[inline(always)]
137    pub fn enable_external_trigger(&self) {
138        self.regs().ctrl0().write(|w| w.ext_trig_en().set_bit());
139    }
140
141    pub fn is_settled(&self) -> nb::Result<(), ()> {
142        if self.regs().status().read().dac_busy().bit_is_set() {
143            return Err(nb::Error::WouldBlock);
144        }
145        Ok(())
146    }
147
148    #[inline(always)]
149    pub fn reset(&mut self) {
150        enable_peripheral_clock(PeripheralSelect::Dac);
151        reset_peripheral_for_cycles(PeripheralSelect::Dac, 2);
152    }
153
154    /// Stops the DAC, which disables its peripheral clock.
155    #[inline(always)]
156    pub fn stop(self) {
157        disable_peripheral_clock(PeripheralSelect::Dac);
158    }
159}