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);