embassy_stm32/dac/
mod.rs

1//! Digital to Analog Converter (DAC)
2#![macro_use]
3
4use core::marker::PhantomData;
5
6use crate::dma::ChannelAndRequest;
7use crate::mode::{Async, Blocking, Mode as PeriMode};
8#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
9use crate::pac::dac;
10use crate::rcc::{self, RccPeripheral};
11use crate::{peripherals, Peri};
12
13mod tsel;
14use embassy_hal_internal::PeripheralType;
15pub use tsel::TriggerSel;
16
17/// Operating mode for DAC channel
18#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
19#[derive(Debug, Copy, Clone, Eq, PartialEq)]
20#[cfg_attr(feature = "defmt", derive(defmt::Format))]
21pub enum Mode {
22    /// Normal mode, channel is connected to external pin with buffer enabled.
23    NormalExternalBuffered,
24    /// Normal mode, channel is connected to external pin and internal peripherals
25    /// with buffer enabled.
26    NormalBothBuffered,
27    /// Normal mode, channel is connected to external pin with buffer disabled.
28    NormalExternalUnbuffered,
29    /// Normal mode, channel is connected to internal peripherals with buffer disabled.
30    NormalInternalUnbuffered,
31    /// Sample-and-hold mode, channel is connected to external pin with buffer enabled.
32    SampleHoldExternalBuffered,
33    /// Sample-and-hold mode, channel is connected to external pin and internal peripherals
34    /// with buffer enabled.
35    SampleHoldBothBuffered,
36    /// Sample-and-hold mode, channel is connected to external pin and internal peripherals
37    /// with buffer disabled.
38    SampleHoldBothUnbuffered,
39    /// Sample-and-hold mode, channel is connected to internal peripherals with buffer disabled.
40    SampleHoldInternalUnbuffered,
41}
42
43#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
44impl Mode {
45    fn mode(&self) -> dac::vals::Mode {
46        match self {
47            Mode::NormalExternalBuffered => dac::vals::Mode::NORMAL_EXT_BUFEN,
48            Mode::NormalBothBuffered => dac::vals::Mode::NORMAL_EXT_INT_BUFEN,
49            Mode::NormalExternalUnbuffered => dac::vals::Mode::NORMAL_EXT_BUFDIS,
50            Mode::NormalInternalUnbuffered => dac::vals::Mode::NORMAL_INT_BUFDIS,
51            Mode::SampleHoldExternalBuffered => dac::vals::Mode::SAMPHOLD_EXT_BUFEN,
52            Mode::SampleHoldBothBuffered => dac::vals::Mode::SAMPHOLD_EXT_INT_BUFEN,
53            Mode::SampleHoldBothUnbuffered => dac::vals::Mode::SAMPHOLD_EXT_INT_BUFDIS,
54            Mode::SampleHoldInternalUnbuffered => dac::vals::Mode::SAMPHOLD_INT_BUFDIS,
55        }
56    }
57}
58
59#[derive(Debug, Copy, Clone, Eq, PartialEq)]
60#[cfg_attr(feature = "defmt", derive(defmt::Format))]
61/// Single 8 or 12 bit value that can be output by the DAC.
62///
63/// 12-bit values outside the permitted range are silently truncated.
64pub enum Value {
65    /// 8 bit value
66    Bit8(u8),
67    /// 12 bit value stored in a u16, left-aligned
68    Bit12Left(u16),
69    /// 12 bit value stored in a u16, right-aligned
70    Bit12Right(u16),
71}
72
73#[derive(Debug, Copy, Clone, Eq, PartialEq)]
74#[cfg_attr(feature = "defmt", derive(defmt::Format))]
75/// Dual 8 or 12 bit values that can be output by the DAC channels 1 and 2 simultaneously.
76///
77/// 12-bit values outside the permitted range are silently truncated.
78pub enum DualValue {
79    /// 8 bit value
80    Bit8(u8, u8),
81    /// 12 bit value stored in a u16, left-aligned
82    Bit12Left(u16, u16),
83    /// 12 bit value stored in a u16, right-aligned
84    Bit12Right(u16, u16),
85}
86
87#[derive(Debug, Copy, Clone, Eq, PartialEq)]
88#[cfg_attr(feature = "defmt", derive(defmt::Format))]
89/// Array variant of [`Value`].
90pub enum ValueArray<'a> {
91    /// 8 bit values
92    Bit8(&'a [u8]),
93    /// 12 bit value stored in a u16, left-aligned
94    Bit12Left(&'a [u16]),
95    /// 12 bit values stored in a u16, right-aligned
96    Bit12Right(&'a [u16]),
97}
98
99/// Driver for a single DAC channel.
100///
101/// If you want to use both channels, either together or independently,
102/// create a [`Dac`] first and use it to access each channel.
103pub struct DacChannel<'d, T: Instance, C: Channel, M: PeriMode> {
104    phantom: PhantomData<&'d mut (T, C, M)>,
105    #[allow(unused)]
106    dma: Option<ChannelAndRequest<'d>>,
107}
108
109/// DAC channel 1 type alias.
110pub type DacCh1<'d, T, M> = DacChannel<'d, T, Ch1, M>;
111/// DAC channel 2 type alias.
112pub type DacCh2<'d, T, M> = DacChannel<'d, T, Ch2, M>;
113
114impl<'d, T: Instance, C: Channel> DacChannel<'d, T, C, Async> {
115    /// Create a new `DacChannel` instance, consuming the underlying DAC peripheral.
116    ///
117    /// The channel is enabled on creation and begin to drive the output pin.
118    /// Note that some methods, such as `set_trigger()` and `set_mode()`, will
119    /// disable the channel; you must re-enable it with `enable()`.
120    ///
121    /// By default, triggering is disabled, but it can be enabled using
122    /// [`DacChannel::set_trigger()`].
123    pub fn new(peri: Peri<'d, T>, dma: Peri<'d, impl Dma<T, C>>, pin: Peri<'d, impl DacPin<T, C>>) -> Self {
124        pin.set_as_analog();
125        Self::new_inner(
126            peri,
127            new_dma!(dma),
128            #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
129            Mode::NormalExternalBuffered,
130        )
131    }
132
133    /// Create a new `DacChannel` instance where the external output pin is not used,
134    /// so the DAC can only be used to generate internal signals.
135    /// The GPIO pin is therefore available to be used for other functions.
136    ///
137    /// The channel is set to [`Mode::NormalInternalUnbuffered`] and enabled on creation.
138    /// Note that some methods, such as `set_trigger()` and `set_mode()`, will disable the
139    /// channel; you must re-enable it with `enable()`.
140    ///
141    /// By default, triggering is disabled, but it can be enabled using
142    /// [`DacChannel::set_trigger()`].
143    #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))]
144    pub fn new_internal(peri: Peri<'d, T>, dma: Peri<'d, impl Dma<T, C>>) -> Self {
145        Self::new_inner(peri, new_dma!(dma), Mode::NormalInternalUnbuffered)
146    }
147
148    /// Write `data` to this channel via DMA.
149    ///
150    /// To prevent delays or glitches when outputing a periodic waveform, the `circular`
151    /// flag can be set. This configures a circular DMA transfer that continually outputs
152    /// `data`. Note that for performance reasons in circular mode the transfer-complete
153    /// interrupt is disabled.
154    #[cfg(not(gpdma))]
155    pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) {
156        // Enable DAC and DMA
157        T::regs().cr().modify(|w| {
158            w.set_en(C::IDX, true);
159            w.set_dmaen(C::IDX, true);
160        });
161
162        let dma = self.dma.as_mut().unwrap();
163
164        let tx_options = crate::dma::TransferOptions {
165            circular,
166            half_transfer_ir: false,
167            complete_transfer_ir: !circular,
168            ..Default::default()
169        };
170
171        // Initiate the correct type of DMA transfer depending on what data is passed
172        let tx_f = match data {
173            ValueArray::Bit8(buf) => unsafe { dma.write(buf, T::regs().dhr8r(C::IDX).as_ptr() as *mut u8, tx_options) },
174            ValueArray::Bit12Left(buf) => unsafe {
175                dma.write(buf, T::regs().dhr12l(C::IDX).as_ptr() as *mut u16, tx_options)
176            },
177            ValueArray::Bit12Right(buf) => unsafe {
178                dma.write(buf, T::regs().dhr12r(C::IDX).as_ptr() as *mut u16, tx_options)
179            },
180        };
181
182        tx_f.await;
183
184        T::regs().cr().modify(|w| {
185            w.set_en(C::IDX, false);
186            w.set_dmaen(C::IDX, false);
187        });
188    }
189}
190
191impl<'d, T: Instance, C: Channel> DacChannel<'d, T, C, Blocking> {
192    /// Create a new `DacChannel` instance, consuming the underlying DAC peripheral.
193    ///
194    /// The channel is enabled on creation and begin to drive the output pin.
195    /// Note that some methods, such as `set_trigger()` and `set_mode()`, will
196    /// disable the channel; you must re-enable it with `enable()`.
197    ///
198    /// By default, triggering is disabled, but it can be enabled using
199    /// [`DacChannel::set_trigger()`].
200    pub fn new_blocking(peri: Peri<'d, T>, pin: Peri<'d, impl DacPin<T, C>>) -> Self {
201        pin.set_as_analog();
202        Self::new_inner(
203            peri,
204            None,
205            #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
206            Mode::NormalExternalBuffered,
207        )
208    }
209
210    /// Create a new `DacChannel` instance where the external output pin is not used,
211    /// so the DAC can only be used to generate internal signals.
212    /// The GPIO pin is therefore available to be used for other functions.
213    ///
214    /// The channel is set to [`Mode::NormalInternalUnbuffered`] and enabled on creation.
215    /// Note that some methods, such as `set_trigger()` and `set_mode()`, will disable the
216    /// channel; you must re-enable it with `enable()`.
217    ///
218    /// By default, triggering is disabled, but it can be enabled using
219    /// [`DacChannel::set_trigger()`].
220    #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))]
221    pub fn new_internal_blocking(peri: Peri<'d, T>) -> Self {
222        Self::new_inner(peri, None, Mode::NormalInternalUnbuffered)
223    }
224}
225
226impl<'d, T: Instance, C: Channel, M: PeriMode> DacChannel<'d, T, C, M> {
227    fn new_inner(
228        _peri: Peri<'d, T>,
229        dma: Option<ChannelAndRequest<'d>>,
230        #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] mode: Mode,
231    ) -> Self {
232        rcc::enable_and_reset::<T>();
233        let mut dac = Self {
234            phantom: PhantomData,
235            dma,
236        };
237        #[cfg(any(dac_v5, dac_v6, dac_v7))]
238        dac.set_hfsel();
239        #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
240        dac.set_mode(mode);
241        dac.enable();
242        dac
243    }
244
245    /// Enable or disable this channel.
246    pub fn set_enable(&mut self, on: bool) {
247        critical_section::with(|_| {
248            T::regs().cr().modify(|reg| {
249                reg.set_en(C::IDX, on);
250            });
251        });
252    }
253
254    /// Enable this channel.
255    pub fn enable(&mut self) {
256        self.set_enable(true)
257    }
258
259    /// Disable this channel.
260    pub fn disable(&mut self) {
261        self.set_enable(false)
262    }
263
264    /// Set the trigger source for this channel.
265    ///
266    /// This method disables the channel, so you may need to re-enable afterwards.
267    pub fn set_trigger(&mut self, source: TriggerSel) {
268        critical_section::with(|_| {
269            T::regs().cr().modify(|reg| {
270                reg.set_en(C::IDX, false);
271                reg.set_tsel(C::IDX, source as u8);
272            });
273        });
274    }
275
276    /// Enable or disable triggering for this channel.
277    pub fn set_triggering(&mut self, on: bool) {
278        critical_section::with(|_| {
279            T::regs().cr().modify(|reg| {
280                reg.set_ten(C::IDX, on);
281            });
282        });
283    }
284
285    /// Software trigger this channel.
286    pub fn trigger(&mut self) {
287        T::regs().swtrigr().write(|reg| {
288            reg.set_swtrig(C::IDX, true);
289        });
290    }
291
292    /// Set mode of this channel.
293    ///
294    /// This method disables the channel, so you may need to re-enable afterwards.
295    #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
296    pub fn set_mode(&mut self, mode: Mode) {
297        critical_section::with(|_| {
298            T::regs().cr().modify(|reg| {
299                reg.set_en(C::IDX, false);
300            });
301            T::regs().mcr().modify(|reg| {
302                reg.set_mode(C::IDX, mode.mode());
303            });
304        });
305    }
306
307    /// Write a new value to this channel.
308    ///
309    /// If triggering is not enabled, the new value is immediately output; otherwise,
310    /// it will be output after the next trigger.
311    pub fn set(&mut self, value: Value) {
312        match value {
313            Value::Bit8(v) => T::regs().dhr8r(C::IDX).write(|reg| reg.set_dhr(v)),
314            Value::Bit12Left(v) => T::regs().dhr12l(C::IDX).write(|reg| reg.set_dhr(v)),
315            Value::Bit12Right(v) => T::regs().dhr12r(C::IDX).write(|reg| reg.set_dhr(v)),
316        }
317    }
318
319    /// Read the current output value of the DAC.
320    pub fn read(&self) -> u16 {
321        T::regs().dor(C::IDX).read().dor()
322    }
323
324    /// Set HFSEL as appropriate for the current peripheral clock frequency.
325    #[cfg(dac_v5)]
326    fn set_hfsel(&mut self) {
327        if T::frequency() >= crate::time::mhz(80) {
328            critical_section::with(|_| {
329                T::regs().cr().modify(|reg| {
330                    reg.set_hfsel(true);
331                });
332            });
333        }
334    }
335
336    /// Set HFSEL as appropriate for the current peripheral clock frequency.
337    #[cfg(any(dac_v6, dac_v7))]
338    fn set_hfsel(&mut self) {
339        if T::frequency() >= crate::time::mhz(160) {
340            critical_section::with(|_| {
341                T::regs().mcr().modify(|reg| {
342                    reg.set_hfsel(0b10);
343                });
344            });
345        } else if T::frequency() >= crate::time::mhz(80) {
346            critical_section::with(|_| {
347                T::regs().mcr().modify(|reg| {
348                    reg.set_hfsel(0b01);
349                });
350            });
351        }
352    }
353}
354
355impl<'d, T: Instance, C: Channel, M: PeriMode> Drop for DacChannel<'d, T, C, M> {
356    fn drop(&mut self) {
357        rcc::disable::<T>();
358    }
359}
360
361/// DAC driver.
362///
363/// Use this struct when you want to use both channels, either together or independently.
364///
365/// # Example
366///
367/// ```ignore
368/// // Pins may need to be changed for your specific device.
369/// let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new_blocking(p.DAC1, p.PA4, p.PA5).split();
370/// ```
371pub struct Dac<'d, T: Instance, M: PeriMode> {
372    ch1: DacChannel<'d, T, Ch1, M>,
373    ch2: DacChannel<'d, T, Ch2, M>,
374}
375
376impl<'d, T: Instance> Dac<'d, T, Async> {
377    /// Create a new `Dac` instance, consuming the underlying DAC peripheral.
378    ///
379    /// This struct allows you to access both channels of the DAC, where available. You can either
380    /// call `split()` to obtain separate `DacChannel`s, or use methods on `Dac` to use
381    /// the two channels together.
382    ///
383    /// The channels are enabled on creation and begin to drive their output pins.
384    /// Note that some methods, such as `set_trigger()` and `set_mode()`, will
385    /// disable the channel; you must re-enable them with `enable()`.
386    ///
387    /// By default, triggering is disabled, but it can be enabled using the `set_trigger()`
388    /// method on the underlying channels.
389    pub fn new(
390        peri: Peri<'d, T>,
391        dma_ch1: Peri<'d, impl Dma<T, Ch1>>,
392        dma_ch2: Peri<'d, impl Dma<T, Ch2>>,
393        pin_ch1: Peri<'d, impl DacPin<T, Ch1> + crate::gpio::Pin>,
394        pin_ch2: Peri<'d, impl DacPin<T, Ch2> + crate::gpio::Pin>,
395    ) -> Self {
396        pin_ch1.set_as_analog();
397        pin_ch2.set_as_analog();
398        Self::new_inner(
399            peri,
400            new_dma!(dma_ch1),
401            new_dma!(dma_ch2),
402            #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
403            Mode::NormalExternalBuffered,
404        )
405    }
406    /// Create a new `Dac` instance with external output pins and unbuffered mode.
407    ///
408    /// This function consumes the underlying DAC peripheral and allows access to both channels.
409    /// The channels are configured for external output with the buffer disabled.
410    ///
411    /// The channels are enabled on creation and begin to drive their output pins.
412    /// Note that some methods, such as `set_trigger()` and `set_mode()`, will
413    /// disable the channel; you must re-enable them with `enable()`.
414    ///
415    /// By default, triggering is disabled, but it can be enabled using the `set_trigger()`
416    /// method on the underlying channels.
417    ///
418    /// # Arguments
419    ///
420    /// * `peri` - The DAC peripheral instance.
421    /// * `dma_ch1` - The DMA channel for DAC channel 1.
422    /// * `dma_ch2` - The DMA channel for DAC channel 2.
423    /// * `pin_ch1` - The GPIO pin for DAC channel 1 output.
424    /// * `pin_ch2` - The GPIO pin for DAC channel 2 output.
425    ///
426    /// # Returns
427    ///
428    /// A new `Dac` instance in unbuffered mode.
429    pub fn new_unbuffered(
430        peri: Peri<'d, T>,
431        dma_ch1: Peri<'d, impl Dma<T, Ch1>>,
432        dma_ch2: Peri<'d, impl Dma<T, Ch2>>,
433        pin_ch1: Peri<'d, impl DacPin<T, Ch1> + crate::gpio::Pin>,
434        pin_ch2: Peri<'d, impl DacPin<T, Ch2> + crate::gpio::Pin>,
435    ) -> Self {
436        pin_ch1.set_as_analog();
437        pin_ch2.set_as_analog();
438        Self::new_inner(
439            peri,
440            new_dma!(dma_ch1),
441            new_dma!(dma_ch2),
442            #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
443            Mode::NormalExternalUnbuffered,
444        )
445    }
446
447    /// Create a new `Dac` instance where the external output pins are not used,
448    /// so the DAC can only be used to generate internal signals but the GPIO
449    /// pins remain available for other functions.
450    ///
451    /// This struct allows you to access both channels of the DAC, where available. You can either
452    /// call `split()` to obtain separate `DacChannel`s, or use methods on `Dac` to use the two
453    /// channels together.
454    ///
455    /// The channels are set to [`Mode::NormalInternalUnbuffered`] and enabled on creation.
456    /// Note that some methods, such as `set_trigger()` and `set_mode()`, will disable the
457    /// channel; you must re-enable them with `enable()`.
458    ///
459    /// By default, triggering is disabled, but it can be enabled using the `set_trigger()`
460    /// method on the underlying channels.
461    #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))]
462    pub fn new_internal(
463        peri: Peri<'d, T>,
464        dma_ch1: Peri<'d, impl Dma<T, Ch1>>,
465        dma_ch2: Peri<'d, impl Dma<T, Ch2>>,
466    ) -> Self {
467        Self::new_inner(
468            peri,
469            new_dma!(dma_ch1),
470            new_dma!(dma_ch2),
471            Mode::NormalInternalUnbuffered,
472        )
473    }
474}
475
476impl<'d, T: Instance> Dac<'d, T, Blocking> {
477    /// Create a new `Dac` instance, consuming the underlying DAC peripheral.
478    ///
479    /// This struct allows you to access both channels of the DAC, where available. You can either
480    /// call `split()` to obtain separate `DacChannel`s, or use methods on `Dac` to use
481    /// the two channels together.
482    ///
483    /// The channels are enabled on creation and begin to drive their output pins.
484    /// Note that some methods, such as `set_trigger()` and `set_mode()`, will
485    /// disable the channel; you must re-enable them with `enable()`.
486    ///
487    /// By default, triggering is disabled, but it can be enabled using the `set_trigger()`
488    /// method on the underlying channels.
489    pub fn new_blocking(
490        peri: Peri<'d, T>,
491        pin_ch1: Peri<'d, impl DacPin<T, Ch1> + crate::gpio::Pin>,
492        pin_ch2: Peri<'d, impl DacPin<T, Ch2> + crate::gpio::Pin>,
493    ) -> Self {
494        pin_ch1.set_as_analog();
495        pin_ch2.set_as_analog();
496        Self::new_inner(
497            peri,
498            None,
499            None,
500            #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
501            Mode::NormalExternalBuffered,
502        )
503    }
504
505    /// Create a new `Dac` instance where the external output pins are not used,
506    /// so the DAC can only be used to generate internal signals but the GPIO
507    /// pins remain available for other functions.
508    ///
509    /// This struct allows you to access both channels of the DAC, where available. You can either
510    /// call `split()` to obtain separate `DacChannel`s, or use methods on `Dac` to use the two
511    /// channels together.
512    ///
513    /// The channels are set to [`Mode::NormalInternalUnbuffered`] and enabled on creation.
514    /// Note that some methods, such as `set_trigger()` and `set_mode()`, will disable the
515    /// channel; you must re-enable them with `enable()`.
516    ///
517    /// By default, triggering is disabled, but it can be enabled using the `set_trigger()`
518    /// method on the underlying channels.
519    #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))]
520    pub fn new_internal(peri: Peri<'d, T>) -> Self {
521        Self::new_inner(peri, None, None, Mode::NormalInternalUnbuffered)
522    }
523}
524
525impl<'d, T: Instance, M: PeriMode> Dac<'d, T, M> {
526    fn new_inner(
527        _peri: Peri<'d, T>,
528        dma_ch1: Option<ChannelAndRequest<'d>>,
529        dma_ch2: Option<ChannelAndRequest<'d>>,
530        #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] mode: Mode,
531    ) -> Self {
532        // Enable twice to increment the DAC refcount for each channel.
533        rcc::enable_and_reset::<T>();
534        rcc::enable_and_reset::<T>();
535
536        let mut ch1 = DacCh1 {
537            phantom: PhantomData,
538            dma: dma_ch1,
539        };
540        #[cfg(any(dac_v5, dac_v6, dac_v7))]
541        ch1.set_hfsel();
542        #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
543        ch1.set_mode(mode);
544        ch1.enable();
545
546        let mut ch2 = DacCh2 {
547            phantom: PhantomData,
548            dma: dma_ch2,
549        };
550        #[cfg(any(dac_v5, dac_v6, dac_v7))]
551        ch2.set_hfsel();
552        #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
553        ch2.set_mode(mode);
554        ch2.enable();
555
556        Self { ch1, ch2 }
557    }
558
559    /// Split this `Dac` into separate channels.
560    ///
561    /// You can access and move the channels around separately after splitting.
562    pub fn split(self) -> (DacCh1<'d, T, M>, DacCh2<'d, T, M>) {
563        (self.ch1, self.ch2)
564    }
565
566    /// Temporarily access channel 1.
567    pub fn ch1(&mut self) -> &mut DacCh1<'d, T, M> {
568        &mut self.ch1
569    }
570
571    /// Temporarily access channel 2.
572    pub fn ch2(&mut self) -> &mut DacCh2<'d, T, M> {
573        &mut self.ch2
574    }
575
576    /// Simultaneously update channels 1 and 2 with a new value.
577    ///
578    /// If triggering is not enabled, the new values are immediately output;
579    /// otherwise, they will be output after the next trigger.
580    pub fn set(&mut self, values: DualValue) {
581        match values {
582            DualValue::Bit8(v1, v2) => T::regs().dhr8rd().write(|reg| {
583                reg.set_dhr(0, v1);
584                reg.set_dhr(1, v2);
585            }),
586            DualValue::Bit12Left(v1, v2) => T::regs().dhr12ld().write(|reg| {
587                reg.set_dhr(0, v1);
588                reg.set_dhr(1, v2);
589            }),
590            DualValue::Bit12Right(v1, v2) => T::regs().dhr12rd().write(|reg| {
591                reg.set_dhr(0, v1);
592                reg.set_dhr(1, v2);
593            }),
594        }
595    }
596}
597
598trait SealedInstance {
599    fn regs() -> crate::pac::dac::Dac;
600}
601
602/// DAC instance.
603#[allow(private_bounds)]
604pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + 'static {}
605
606/// Channel 1 marker type.
607pub enum Ch1 {}
608/// Channel 2 marker type.
609pub enum Ch2 {}
610
611trait SealedChannel {
612    const IDX: usize;
613}
614/// DAC channel trait.
615#[allow(private_bounds)]
616pub trait Channel: SealedChannel {}
617
618impl SealedChannel for Ch1 {
619    const IDX: usize = 0;
620}
621impl SealedChannel for Ch2 {
622    const IDX: usize = 1;
623}
624impl Channel for Ch1 {}
625impl Channel for Ch2 {}
626
627dma_trait!(Dma, Instance, Channel);
628pin_trait!(DacPin, Instance, Channel);
629
630foreach_peripheral!(
631    (dac, $inst:ident) => {
632        impl crate::dac::SealedInstance for peripherals::$inst {
633            fn regs() -> crate::pac::dac::Dac {
634                crate::pac::$inst
635            }
636        }
637
638        impl crate::dac::Instance for peripherals::$inst {}
639    };
640);