1//! Digital to Analog Converter (DAC)
2#![macro_use]
3
4use core::marker::PhantomData;
5
6use embassy_hal_internal::{into_ref, PeripheralRef};
7
8use crate::dma::NoDma;
9#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
10use crate::pac::dac;
11use crate::rcc::{self, RccPeripheral};
12use crate::{peripherals, Peripheral};
13
14mod tsel;
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, const N: u8, DMA = NoDma> {
104 phantom: PhantomData<&'d mut T>,
105 #[allow(unused)]
106 dma: PeripheralRef<'d, DMA>,
107}
108
109/// DAC channel 1 type alias.
110pub type DacCh1<'d, T, DMA = NoDma> = DacChannel<'d, T, 1, DMA>;
111/// DAC channel 2 type alias.
112pub type DacCh2<'d, T, DMA = NoDma> = DacChannel<'d, T, 2, DMA>;
113
114impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
115 const IDX: usize = (N - 1) as usize;
116
117 /// Create a new `DacChannel` instance, consuming the underlying DAC peripheral.
118 ///
119 /// If you're not using DMA, pass [`dma::NoDma`] for the `dma` argument.
120 ///
121 /// The channel is enabled on creation and begin to drive the output pin.
122 /// Note that some methods, such as `set_trigger()` and `set_mode()`, will
123 /// disable the channel; you must re-enable it with `enable()`.
124 ///
125 /// By default, triggering is disabled, but it can be enabled using
126 /// [`DacChannel::set_trigger()`].
127 pub fn new(
128 _peri: impl Peripheral<P = T> + 'd,
129 dma: impl Peripheral<P = DMA> + 'd,
130 pin: impl Peripheral<P = impl DacPin<T, N> + crate::gpio::Pin> + 'd,
131 ) -> Self {
132 into_ref!(dma, pin);
133 pin.set_as_analog();
134 rcc::enable_and_reset::<T>();
135 let mut dac = Self {
136 phantom: PhantomData,
137 dma,
138 };
139 #[cfg(any(dac_v5, dac_v6, dac_v7))]
140 dac.set_hfsel();
141 dac.enable();
142 dac
143 }
144
145 /// Create a new `DacChannel` instance where the external output pin is not used,
146 /// so the DAC can only be used to generate internal signals.
147 /// The GPIO pin is therefore available to be used for other functions.
148 ///
149 /// The channel is set to [`Mode::NormalInternalUnbuffered`] and enabled on creation.
150 /// Note that some methods, such as `set_trigger()` and `set_mode()`, will disable the
151 /// channel; you must re-enable it with `enable()`.
152 ///
153 /// If you're not using DMA, pass [`dma::NoDma`] for the `dma` argument.
154 ///
155 /// By default, triggering is disabled, but it can be enabled using
156 /// [`DacChannel::set_trigger()`].
157 #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))]
158 pub fn new_internal(_peri: impl Peripheral<P = T> + 'd, dma: impl Peripheral<P = DMA> + 'd) -> Self {
159 into_ref!(dma);
160 rcc::enable_and_reset::<T>();
161 let mut dac = Self {
162 phantom: PhantomData,
163 dma,
164 };
165 #[cfg(any(dac_v5, dac_v6, dac_v7))]
166 dac.set_hfsel();
167 dac.set_mode(Mode::NormalInternalUnbuffered);
168 dac.enable();
169 dac
170 }
171
172 /// Enable or disable this channel.
173 pub fn set_enable(&mut self, on: bool) {
174 critical_section::with(|_| {
175 T::regs().cr().modify(|reg| {
176 reg.set_en(Self::IDX, on);
177 });
178 });
179 }
180
181 /// Enable this channel.
182 pub fn enable(&mut self) {
183 self.set_enable(true)
184 }
185
186 /// Disable this channel.
187 pub fn disable(&mut self) {
188 self.set_enable(false)
189 }
190
191 /// Set the trigger source for this channel.
192 ///
193 /// This method disables the channel, so you may need to re-enable afterwards.
194 pub fn set_trigger(&mut self, source: TriggerSel) {
195 critical_section::with(|_| {
196 T::regs().cr().modify(|reg| {
197 reg.set_en(Self::IDX, false);
198 reg.set_tsel(Self::IDX, source as u8);
199 });
200 });
201 }
202
203 /// Enable or disable triggering for this channel.
204 pub fn set_triggering(&mut self, on: bool) {
205 critical_section::with(|_| {
206 T::regs().cr().modify(|reg| {
207 reg.set_ten(Self::IDX, on);
208 });
209 });
210 }
211
212 /// Software trigger this channel.
213 pub fn trigger(&mut self) {
214 T::regs().swtrigr().write(|reg| {
215 reg.set_swtrig(Self::IDX, true);
216 });
217 }
218
219 /// Set mode of this channel.
220 ///
221 /// This method disables the channel, so you may need to re-enable afterwards.
222 #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
223 pub fn set_mode(&mut self, mode: Mode) {
224 critical_section::with(|_| {
225 T::regs().cr().modify(|reg| {
226 reg.set_en(Self::IDX, false);
227 });
228 T::regs().mcr().modify(|reg| {
229 reg.set_mode(Self::IDX, mode.mode());
230 });
231 });
232 }
233
234 /// Write a new value to this channel.
235 ///
236 /// If triggering is not enabled, the new value is immediately output; otherwise,
237 /// it will be output after the next trigger.
238 pub fn set(&mut self, value: Value) {
239 match value {
240 Value::Bit8(v) => T::regs().dhr8r(Self::IDX).write(|reg| reg.set_dhr(v)),
241 Value::Bit12Left(v) => T::regs().dhr12l(Self::IDX).write(|reg| reg.set_dhr(v)),
242 Value::Bit12Right(v) => T::regs().dhr12r(Self::IDX).write(|reg| reg.set_dhr(v)),
243 }
244 }
245
246 /// Read the current output value of the DAC.
247 pub fn read(&self) -> u16 {
248 T::regs().dor(Self::IDX).read().dor()
249 }
250
251 /// Set HFSEL as appropriate for the current peripheral clock frequency.
252 #[cfg(dac_v5)]
253 fn set_hfsel(&mut self) {
254 if T::frequency() >= crate::time::mhz(80) {
255 critical_section::with(|_| {
256 T::regs().cr().modify(|reg| {
257 reg.set_hfsel(true);
258 });
259 });
260 }
261 }
262
263 /// Set HFSEL as appropriate for the current peripheral clock frequency.
264 #[cfg(any(dac_v6, dac_v7))]
265 fn set_hfsel(&mut self) {
266 if T::frequency() >= crate::time::mhz(160) {
267 critical_section::with(|_| {
268 T::regs().mcr().modify(|reg| {
269 reg.set_hfsel(0b10);
270 });
271 });
272 } else if T::frequency() >= crate::time::mhz(80) {
273 critical_section::with(|_| {
274 T::regs().mcr().modify(|reg| {
275 reg.set_hfsel(0b01);
276 });
277 });
278 }
279 }
280}
281
282macro_rules! impl_dma_methods {
283 ($n:literal, $trait:ident) => {
284 impl<'d, T: Instance, DMA> DacChannel<'d, T, $n, DMA>
285 where
286 DMA: $trait<T>,
287 {
288 /// Write `data` to this channel via DMA.
289 ///
290 /// To prevent delays or glitches when outputing a periodic waveform, the `circular`
291 /// flag can be set. This configures a circular DMA transfer that continually outputs
292 /// `data`. Note that for performance reasons in circular mode the transfer-complete
293 /// interrupt is disabled.
294 #[cfg(not(gpdma))]
295 pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) {
296 // Enable DAC and DMA
297 T::regs().cr().modify(|w| {
298 w.set_en(Self::IDX, true);
299 w.set_dmaen(Self::IDX, true);
300 });
301
302 let tx_request = self.dma.request();
303 let dma_channel = &mut self.dma;
304
305 let tx_options = crate::dma::TransferOptions {
306 circular,
307 half_transfer_ir: false,
308 complete_transfer_ir: !circular,
309 ..Default::default()
310 };
311
312 // Initiate the correct type of DMA transfer depending on what data is passed
313 let tx_f = match data {
314 ValueArray::Bit8(buf) => unsafe {
315 crate::dma::Transfer::new_write(
316 dma_channel,
317 tx_request,
318 buf,
319 T::regs().dhr8r(Self::IDX).as_ptr() as *mut u8,
320 tx_options,
321 )
322 },
323 ValueArray::Bit12Left(buf) => unsafe {
324 crate::dma::Transfer::new_write(
325 dma_channel,
326 tx_request,
327 buf,
328 T::regs().dhr12l(Self::IDX).as_ptr() as *mut u16,
329 tx_options,
330 )
331 },
332 ValueArray::Bit12Right(buf) => unsafe {
333 crate::dma::Transfer::new_write(
334 dma_channel,
335 tx_request,
336 buf,
337 T::regs().dhr12r(Self::IDX).as_ptr() as *mut u16,
338 tx_options,
339 )
340 },
341 };
342
343 tx_f.await;
344
345 T::regs().cr().modify(|w| {
346 w.set_en(Self::IDX, false);
347 w.set_dmaen(Self::IDX, false);
348 });
349 }
350 }
351 };
352}
353
354impl_dma_methods!(1, DacDma1);
355impl_dma_methods!(2, DacDma2);
356
357impl<'d, T: Instance, const N: u8, DMA> Drop for DacChannel<'d, T, N, DMA> {
358 fn drop(&mut self) {
359 rcc::disable::<T>();
360 }
361}
362
363/// DAC driver.
364///
365/// Use this struct when you want to use both channels, either together or independently.
366///
367/// # Example
368///
369/// ```ignore
370/// // Pins may need to be changed for your specific device.
371/// let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, NoDma, NoDma, p.PA4, p.PA5).split();
372/// ```
373pub struct Dac<'d, T: Instance, DMACh1 = NoDma, DMACh2 = NoDma> {
374 ch1: DacChannel<'d, T, 1, DMACh1>,
375 ch2: DacChannel<'d, T, 2, DMACh2>,
376}
377
378impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
379 /// Create a new `Dac` instance, consuming the underlying DAC peripheral.
380 ///
381 /// This struct allows you to access both channels of the DAC, where available. You can either
382 /// call `split()` to obtain separate `DacChannel`s, or use methods on `Dac` to use
383 /// the two channels together.
384 ///
385 /// The channels are enabled on creation and begin to drive their output pins.
386 /// Note that some methods, such as `set_trigger()` and `set_mode()`, will
387 /// disable the channel; you must re-enable them with `enable()`.
388 ///
389 /// By default, triggering is disabled, but it can be enabled using the `set_trigger()`
390 /// method on the underlying channels.
391 pub fn new(
392 _peri: impl Peripheral<P = T> + 'd,
393 dma_ch1: impl Peripheral<P = DMACh1> + 'd,
394 dma_ch2: impl Peripheral<P = DMACh2> + 'd,
395 pin_ch1: impl Peripheral<P = impl DacPin<T, 1> + crate::gpio::Pin> + 'd,
396 pin_ch2: impl Peripheral<P = impl DacPin<T, 2> + crate::gpio::Pin> + 'd,
397 ) -> Self {
398 into_ref!(dma_ch1, dma_ch2, pin_ch1, pin_ch2);
399 pin_ch1.set_as_analog();
400 pin_ch2.set_as_analog();
401
402 // Enable twice to increment the DAC refcount for each channel.
403 rcc::enable_and_reset::<T>();
404 rcc::enable_and_reset::<T>();
405
406 let mut ch1 = DacCh1 {
407 phantom: PhantomData,
408 dma: dma_ch1,
409 };
410 #[cfg(any(dac_v5, dac_v6, dac_v7))]
411 ch1.set_hfsel();
412 ch1.enable();
413
414 let mut ch2 = DacCh2 {
415 phantom: PhantomData,
416 dma: dma_ch2,
417 };
418 #[cfg(any(dac_v5, dac_v6, dac_v7))]
419 ch2.set_hfsel();
420 ch2.enable();
421
422 Self { ch1, ch2 }
423 }
424
425 /// Create a new `Dac` instance where the external output pins are not used,
426 /// so the DAC can only be used to generate internal signals but the GPIO
427 /// pins remain available for other functions.
428 ///
429 /// This struct allows you to access both channels of the DAC, where available. You can either
430 /// call `split()` to obtain separate `DacChannel`s, or use methods on `Dac` to use the two
431 /// channels together.
432 ///
433 /// The channels are set to [`Mode::NormalInternalUnbuffered`] and enabled on creation.
434 /// Note that some methods, such as `set_trigger()` and `set_mode()`, will disable the
435 /// channel; you must re-enable them with `enable()`.
436 ///
437 /// By default, triggering is disabled, but it can be enabled using the `set_trigger()`
438 /// method on the underlying channels.
439 #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))]
440 pub fn new_internal(
441 _peri: impl Peripheral<P = T> + 'd,
442 dma_ch1: impl Peripheral<P = DMACh1> + 'd,
443 dma_ch2: impl Peripheral<P = DMACh2> + 'd,
444 ) -> Self {
445 into_ref!(dma_ch1, dma_ch2);
446 // Enable twice to increment the DAC refcount for each channel.
447 rcc::enable_and_reset::<T>();
448 rcc::enable_and_reset::<T>();
449
450 let mut ch1 = DacCh1 {
451 phantom: PhantomData,
452 dma: dma_ch1,
453 };
454 #[cfg(any(dac_v5, dac_v6, dac_v7))]
455 ch1.set_hfsel();
456 ch1.set_mode(Mode::NormalInternalUnbuffered);
457 ch1.enable();
458
459 let mut ch2 = DacCh2 {
460 phantom: PhantomData,
461 dma: dma_ch2,
462 };
463 #[cfg(any(dac_v5, dac_v6, dac_v7))]
464 ch2.set_hfsel();
465 ch2.set_mode(Mode::NormalInternalUnbuffered);
466 ch2.enable();
467
468 Self { ch1, ch2 }
469 }
470
471 /// Split this `Dac` into separate channels.
472 ///
473 /// You can access and move the channels around separately after splitting.
474 pub fn split(self) -> (DacCh1<'d, T, DMACh1>, DacCh2<'d, T, DMACh2>) {
475 (self.ch1, self.ch2)
476 }
477
478 /// Temporarily access channel 1.
479 pub fn ch1(&mut self) -> &mut DacCh1<'d, T, DMACh1> {
480 &mut self.ch1
481 }
482
483 /// Temporarily access channel 2.
484 pub fn ch2(&mut self) -> &mut DacCh2<'d, T, DMACh2> {
485 &mut self.ch2
486 }
487
488 /// Simultaneously update channels 1 and 2 with a new value.
489 ///
490 /// If triggering is not enabled, the new values are immediately output;
491 /// otherwise, they will be output after the next trigger.
492 pub fn set(&mut self, values: DualValue) {
493 match values {
494 DualValue::Bit8(v1, v2) => T::regs().dhr8rd().write(|reg| {
495 reg.set_dhr(0, v1);
496 reg.set_dhr(1, v2);
497 }),
498 DualValue::Bit12Left(v1, v2) => T::regs().dhr12ld().write(|reg| {
499 reg.set_dhr(0, v1);
500 reg.set_dhr(1, v2);
501 }),
502 DualValue::Bit12Right(v1, v2) => T::regs().dhr12rd().write(|reg| {
503 reg.set_dhr(0, v1);
504 reg.set_dhr(1, v2);
505 }),
506 }
507 }
508}
509
510trait SealedInstance {
511 fn regs() -> crate::pac::dac::Dac;
512}
513
514/// DAC instance.
515#[allow(private_bounds)]
516pub trait Instance: SealedInstance + RccPeripheral + 'static {}
517dma_trait!(DacDma1, Instance);
518dma_trait!(DacDma2, Instance);
519
520/// Marks a pin that can be used with the DAC
521pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
522
523foreach_peripheral!(
524 (dac, $inst:ident) => {
525 impl crate::dac::SealedInstance for peripherals::$inst {
526 fn regs() -> crate::pac::dac::Dac {
527 crate::pac::$inst
528 }
529 }
530
531 impl crate::dac::Instance for peripherals::$inst {}
532 };
533);
534
535macro_rules! impl_dac_pin {
536 ($inst:ident, $pin:ident, $ch:expr) => {
537 impl crate::dac::DacPin<peripherals::$inst, $ch> for crate::peripherals::$pin {}
538 };
539}
540