1#![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#[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 NormalExternalBuffered,
24 NormalBothBuffered,
27 NormalExternalUnbuffered,
29 NormalInternalUnbuffered,
31 SampleHoldExternalBuffered,
33 SampleHoldBothBuffered,
36 SampleHoldBothUnbuffered,
39 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))]
61pub enum Value {
65 Bit8(u8),
67 Bit12Left(u16),
69 Bit12Right(u16),
71}
72
73#[derive(Debug, Copy, Clone, Eq, PartialEq)]
74#[cfg_attr(feature = "defmt", derive(defmt::Format))]
75pub enum DualValue {
79 Bit8(u8, u8),
81 Bit12Left(u16, u16),
83 Bit12Right(u16, u16),
85}
86
87#[derive(Debug, Copy, Clone, Eq, PartialEq)]
88#[cfg_attr(feature = "defmt", derive(defmt::Format))]
89pub enum ValueArray<'a> {
91 Bit8(&'a [u8]),
93 Bit12Left(&'a [u16]),
95 Bit12Right(&'a [u16]),
97}
98
99pub 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
109pub type DacCh1<'d, T, DMA = NoDma> = DacChannel<'d, T, 1, DMA>;
111pub 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 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 #[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 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 pub fn enable(&mut self) {
183 self.set_enable(true)
184 }
185
186 pub fn disable(&mut self) {
188 self.set_enable(false)
189 }
190
191 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 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 pub fn trigger(&mut self) {
214 T::regs().swtrigr().write(|reg| {
215 reg.set_swtrig(Self::IDX, true);
216 });
217 }
218
219 #[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 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 pub fn read(&self) -> u16 {
248 T::regs().dor(Self::IDX).read().dor()
249 }
250
251 #[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 #[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 #[cfg(not(gpdma))]
295 pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) {
296 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 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
363pub 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 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 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 #[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 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 pub fn split(self) -> (DacCh1<'d, T, DMACh1>, DacCh2<'d, T, DMACh2>) {
475 (self.ch1, self.ch2)
476 }
477
478 pub fn ch1(&mut self) -> &mut DacCh1<'d, T, DMACh1> {
480 &mut self.ch1
481 }
482
483 pub fn ch2(&mut self) -> &mut DacCh2<'d, T, DMACh2> {
485 &mut self.ch2
486 }
487
488 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#[allow(private_bounds)]
516pub trait Instance: SealedInstance + RccPeripheral + 'static {}
517dma_trait!(DacDma1, Instance);
518dma_trait!(DacDma2, Instance);
519
520pub 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}