1pub use embedded_dma::{ReadBuffer, WriteBuffer};
15
16use crate::{
17 pac::{self, dma1::ch::cr},
18 rcc::AHB,
19 serial,
20};
21use core::{
22 convert::TryFrom,
23 mem,
24 sync::atomic::{self, Ordering},
25};
26
27#[cfg(feature = "enumset")]
28use enumset::EnumSetType;
29
30#[allow(clippy::module_name_repetitions)]
32pub trait DmaExt {
33 type Channels;
35
36 fn split(self, ahb: &mut AHB) -> Self::Channels;
38}
39
40pub trait Target {
42 fn enable_dma(&mut self) {}
44 fn disable_dma(&mut self) {}
46}
47
48#[derive(Debug)]
50#[cfg_attr(feature = "defmt", derive(defmt::Format))]
51pub struct Transfer<B, C: Channel, T: Target> {
52 inner: Option<TransferInner<B, C, T>>,
54}
55
56impl<B, C: Channel, T: Target> Transfer<B, C, T> {
57 pub fn start_write(mut buffer: B, mut channel: C, target: T) -> Self
63 where
64 B: WriteBuffer + 'static,
65 T: OnChannel<C>,
66 {
67 let (ptr, len) = unsafe { buffer.write_buffer() };
72 let len = crate::expect!(u16::try_from(len).ok(), "buffer is too large");
73
74 unsafe { channel.set_memory_address(ptr as u32, Increment::Enable) };
77 channel.set_transfer_length(len);
78 channel.set_word_size::<B::Word>();
79 channel.set_direction(Direction::FromPeripheral);
80
81 #[allow(clippy::undocumented_unsafe_blocks)]
84 unsafe {
85 Self::start(buffer, channel, target)
86 }
87 }
88
89 pub fn start_read(buffer: B, mut channel: C, target: T) -> Self
95 where
96 B: ReadBuffer + 'static,
97 T: OnChannel<C>,
98 {
99 let (ptr, len) = unsafe { buffer.read_buffer() };
104 let len = crate::expect!(u16::try_from(len).ok(), "buffer is too large");
105
106 unsafe { channel.set_memory_address(ptr as u32, Increment::Enable) };
109 channel.set_transfer_length(len);
110 channel.set_word_size::<B::Word>();
111 channel.set_direction(Direction::FromMemory);
112
113 #[allow(clippy::undocumented_unsafe_blocks)]
116 unsafe {
117 Self::start(buffer, channel, target)
118 }
119 }
120
121 unsafe fn start(buffer: B, mut channel: C, mut target: T) -> Self
128 where
129 T: OnChannel<C>,
130 {
131 crate::assert!(!channel.is_enabled());
132
133 atomic::compiler_fence(Ordering::Release);
134
135 target.enable_dma();
136 channel.enable();
137
138 Self {
139 inner: Some(TransferInner {
140 buffer,
141 channel,
142 target,
143 }),
144 }
145 }
146
147 pub fn is_complete(&self) -> bool {
153 let inner = crate::unwrap!(self.inner.as_ref());
154 inner.channel.is_event_triggered(Event::TransferComplete)
155 }
156
157 pub fn stop(mut self) -> (B, C, T) {
163 let mut inner = crate::unwrap!(self.inner.take());
164 inner.stop();
165
166 (inner.buffer, inner.channel, inner.target)
167 }
168
169 pub fn wait(self) -> (B, C, T) {
171 while !self.is_complete() {}
172
173 self.stop()
174 }
175}
176
177impl<B, C: Channel, T: Target> Drop for Transfer<B, C, T> {
178 fn drop(&mut self) {
179 if let Some(inner) = self.inner.as_mut() {
180 inner.stop();
181 }
182 }
183}
184
185#[derive(Debug)]
187#[cfg_attr(feature = "defmt", derive(defmt::Format))]
188struct TransferInner<B, C, T> {
189 buffer: B,
190 channel: C,
191 target: T,
192}
193
194impl<B, C: Channel, T: Target> TransferInner<B, C, T> {
195 fn stop(&mut self) {
197 self.channel.disable();
198 self.target.disable_dma();
199
200 atomic::compiler_fence(Ordering::SeqCst);
201 }
202}
203
204#[derive(Debug, Copy, Clone, PartialEq, Eq)]
206#[cfg_attr(feature = "defmt", derive(defmt::Format))]
207pub enum Increment {
208 Enable,
210 Disable,
212}
213
214impl From<Increment> for cr::PINC_A {
215 fn from(inc: Increment) -> Self {
216 match inc {
217 Increment::Enable => cr::PINC_A::Enabled,
218 Increment::Disable => cr::PINC_A::Disabled,
219 }
220 }
221}
222
223#[derive(Debug, Copy, Clone, PartialEq, Eq)]
225#[cfg_attr(feature = "defmt", derive(defmt::Format))]
226pub enum Priority {
227 Low,
229 Medium,
231 High,
233 VeryHigh,
235}
236
237impl From<Priority> for cr::PL_A {
238 fn from(prio: Priority) -> Self {
239 match prio {
240 Priority::Low => cr::PL_A::Low,
241 Priority::Medium => cr::PL_A::Medium,
242 Priority::High => cr::PL_A::High,
243 Priority::VeryHigh => cr::PL_A::VeryHigh,
244 }
245 }
246}
247
248#[derive(Debug, Copy, Clone, PartialEq, Eq)]
250#[cfg_attr(feature = "defmt", derive(defmt::Format))]
251pub enum Direction {
252 FromMemory,
254 FromPeripheral,
256}
257
258impl From<Direction> for cr::DIR_A {
259 fn from(dir: Direction) -> Self {
260 match dir {
261 Direction::FromMemory => cr::DIR_A::FromMemory,
262 Direction::FromPeripheral => cr::DIR_A::FromPeripheral,
263 }
264 }
265}
266
267#[derive(Debug)]
269#[cfg_attr(feature = "defmt", derive(defmt::Format))]
270#[cfg_attr(feature = "enumset", derive(EnumSetType))]
271#[cfg_attr(not(feature = "enumset"), derive(Copy, Clone, PartialEq, Eq))]
272pub enum Event {
273 HalfTransfer,
275 TransferComplete,
277 TransferError,
279 Any,
281}
282
283pub trait Channel: private::Channel {
285 fn is_event_triggered(&self, event: Event) -> bool;
287
288 fn clear_event(&mut self, event: Event);
296
297 fn clear_events(&mut self) {
299 self.clear_event(Event::Any);
300 }
301
302 fn reset(&mut self) {
305 self.ch().cr.reset();
306 self.ch().ndtr.reset();
307 self.ch().par.reset();
308 self.ch().mar.reset();
309 self.clear_event(Event::Any);
310 }
311
312 unsafe fn set_peripheral_address(&mut self, address: u32, inc: Increment) {
326 crate::assert!(!self.is_enabled());
327
328 unsafe {
330 self.ch().par.write(|w| w.pa().bits(address));
331 }
332 self.ch().cr.modify(|_, w| w.pinc().variant(inc.into()));
333 }
334
335 unsafe fn set_memory_address(&mut self, address: u32, inc: Increment) {
349 crate::assert!(!self.is_enabled());
350
351 unsafe {
353 self.ch().mar.write(|w| w.ma().bits(address));
354 }
355 self.ch().cr.modify(|_, w| w.minc().variant(inc.into()));
356 }
357
358 fn set_transfer_length(&mut self, len: u16) {
366 crate::assert!(!self.is_enabled());
367
368 self.ch().ndtr.write(|w| w.ndt().bits(len));
369 }
370
371 fn set_word_size<W>(&mut self) {
377 use cr::PSIZE_A::{Bits16, Bits32, Bits8};
378
379 let psize = match mem::size_of::<W>() {
380 1 => Bits8,
381 2 => Bits16,
382 4 => Bits32,
383 #[cfg(not(feature = "defmt"))]
384 s => core::panic!("unsupported word size: {:?}", s),
385 #[cfg(feature = "defmt")]
386 _ => defmt::panic!("unsupported word size"),
387 };
388
389 self.ch().cr.modify(|_, w| {
390 w.psize().variant(psize);
391 w.msize().variant(psize)
392 });
393 }
394
395 fn set_priority_level(&mut self, priority: Priority) {
397 let pl = priority.into();
398 self.ch().cr.modify(|_, w| w.pl().variant(pl));
399 }
400
401 fn set_direction(&mut self, direction: Direction) {
403 let dir = direction.into();
404 self.ch().cr.modify(|_, w| w.dir().variant(dir));
405 }
406
407 fn configure_intterupt(&mut self, event: Event, enable: bool) {
409 match event {
410 Event::HalfTransfer => self.ch().cr.modify(|_, w| w.htie().bit(enable)),
411 Event::TransferComplete => self.ch().cr.modify(|_, w| w.tcie().bit(enable)),
412 Event::TransferError => self.ch().cr.modify(|_, w| w.teie().bit(enable)),
413 Event::Any => self.ch().cr.modify(|_, w| {
414 w.htie().bit(enable);
415 w.tcie().bit(enable);
416 w.teie().bit(enable)
417 }),
418 }
419 }
420
421 fn enable_interrupt(&mut self, event: Event) {
423 self.configure_intterupt(event, true);
424 }
425
426 fn disable_interrupt(&mut self, event: Event) {
428 self.configure_intterupt(event, false);
429 }
430
431 fn enable(&mut self) {
433 self.clear_event(Event::Any);
434 self.ch().cr.modify(|_, w| w.en().enabled());
435 }
436
437 fn disable(&mut self) {
439 self.ch().cr.modify(|_, w| w.en().disabled());
440 }
441
442 fn is_enabled(&self) -> bool {
444 self.ch().cr.read().en().is_enabled()
445 }
446}
447
448mod private {
449 use crate::pac;
450
451 pub trait Channel {
453 fn ch(&self) -> &pac::dma1::CH;
455 }
456}
457
458macro_rules! dma {
459 (
460 $DMAx:ident, $dmax:ident, $dmaxen:ident,
461 channels: {
462 $( $Ci:ident: (
463 $chi:ident,
464 $htifi:ident, $tcifi:ident, $teifi:ident, $gifi:ident,
465 $chtifi:ident, $ctcifi:ident, $cteifi:ident, $cgifi:ident
466 ), )+
467 },
468 ) => {
469 paste::paste! {
470 #[doc = "All associated types, traits and methods of the `" $DMAx "` peripheral."]
471 pub mod $dmax {
472 use super::*;
473 use crate::pac::$DMAx;
474 use crate::rcc::Enable;
475
476 impl DmaExt for $DMAx {
477 type Channels = Channels;
478
479 fn split(self, ahb: &mut AHB) -> Channels {
480 <$DMAx>::enable(ahb);
481
482 let mut channels = Channels {
483 $( $chi: $Ci { _0: () }, )+
484 };
485
486 channels.reset();
487 channels
488 }
489 }
490
491 #[derive(Debug)]
493 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
494 pub struct Channels {
495 $(
496 pub $chi: $Ci,
498 )+
499 }
500
501 impl Channels {
502 fn reset(&mut self) {
505 $( self.$chi.reset(); )+
506 }
507 }
508
509 $(
510 #[derive(Debug)]
512 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
513 pub struct $Ci {
514 _0: (),
515 }
516
517 impl private::Channel for $Ci {
518 fn ch(&self) -> &pac::dma1::CH {
519 unsafe { &(*$DMAx::ptr()).$chi }
521 }
522 }
523
524 impl Channel for $Ci {
525 fn is_event_triggered(&self, event: Event) -> bool {
526 let flags = unsafe { (*$DMAx::ptr()).isr.read() };
528 match event {
529 Event::HalfTransfer => flags.$htifi().bit_is_set(),
530 Event::TransferComplete => flags.$tcifi().bit_is_set(),
531 Event::TransferError => flags.$teifi().bit_is_set(),
532 Event::Any => flags.$gifi().bit_is_set(),
533 }
534 }
535
536 fn clear_event(&mut self, event: Event) {
537 unsafe {
539 (*$DMAx::ptr()).ifcr.write(|w| match event {
540 Event::HalfTransfer => w.$chtifi().set_bit(),
541 Event::TransferComplete => w.$ctcifi().set_bit(),
542 Event::TransferError => w.$cteifi().set_bit(),
543 Event::Any => w.$cgifi().set_bit(),
544 });
545 }
546 }
547 }
548 )+
549 }
550 }
551 };
552
553 ( $X:literal: {$($C:literal),+} ) => {
554 paste::paste! {
555 dma!(
556 [<DMA $X>], [<dma $X>], [<dma $X en>],
557 channels: {
558 $(
559 [<C $C>]:
560 (
561 [<ch $C>],
562 [<htif $C>],
563 [<tcif $C>],
564 [<teif $C>],
565 [<gif $C>],
566 [<chtif $C>],
567 [<ctcif $C>],
568 [<cteif $C>],
569 [<cgif $C>]
570 ),
571 )+
572 },
573 );
574 }
575 };
576}
577
578dma!( 1: { 1,2,3,4,5,6,7 } );
579
580#[cfg(any(feature = "gpio-f303", feature = "gpio-f303e",))]
581dma!( 2: { 1,2,3,4,5 } );
582
583pub trait OnChannel<C: Channel>: Target + crate::private::Sealed {}
585
586macro_rules! on_channel {
587 (
588 $(
589 $dma:ident: [$(($USART:ty, ($TxChannel:ident, $RxChannel:ident)),)+],
590 ),+
591 ) => {
592 $(
593 $(
594 impl<Tx, Rx> crate::private::Sealed for serial::Serial<$USART, (Tx, Rx)> {}
595 impl<Tx, Rx> OnChannel<$dma::$TxChannel> for serial::Serial<$USART, (Tx, Rx)> {}
596 impl<Tx, Rx> OnChannel<$dma::$RxChannel> for serial::Serial<$USART, (Tx, Rx)> {}
597 )+
598 )+
599 };
600}
601
602on_channel!(
604 dma1: [
605 (pac::USART1, (C4, C5)),
606 (pac::USART2, (C7, C6)),
607 (pac::USART3, (C2, C3)),
608 ],
609);
610
611#[cfg(any(feature = "gpio-f303", feature = "gpio-f303e",))]
612on_channel!(
613 dma2: [
614 (pac::UART4, (C5, C3)),
615 ],
616);