1use core::{
4 fmt,
5 marker::PhantomData,
6 ops::Deref,
7 pin::Pin,
8 sync::atomic::{self, Ordering},
9};
10
11use as_slice::AsSlice;
12
13use crate::{
14 pac::{
15 self,
16 dma2::{self, st::cr},
17 Interrupt, DMA1, DMA2, NVIC,
18 },
19 qspi,
20 rcc::{Enable, RccBus, Reset},
21 serial, spi, state,
22};
23
24pub struct DMA<I> {
26 pub handle: Handle<I, state::Disabled>,
28
29 pub streams: Streams<I>,
31}
32
33impl<I> DMA<I>
34where
35 I: Instance + Enable + Reset,
36{
37 pub fn new(instance: I) -> Self {
41 DMA {
42 handle: Handle::new(instance),
43 streams: Streams::new(),
44 }
45 }
46}
47
48pub struct Handle<I, State> {
53 dma: I,
54 _state: State,
55}
56
57impl<I> Handle<I, state::Disabled>
58where
59 I: Instance + Reset + Enable,
60{
61 fn new(instance: I) -> Self {
62 Self {
63 dma: instance,
64 _state: state::Disabled,
65 }
66 }
67
68 pub fn enable(self, apb: &mut <I as RccBus>::Bus) -> Handle<I, state::Enabled> {
70 I::reset(apb);
71 I::enable(apb);
72
73 Handle {
74 dma: self.dma,
75 _state: state::Enabled,
76 }
77 }
78}
79
80pub struct Transfer<T: Target, B, State> {
85 res: TransferResources<T, B>,
86 _state: State,
87}
88
89impl<T, B> Transfer<T, B, Ready>
90where
91 T: Target,
92 B: 'static,
93{
94 pub(crate) unsafe fn new<Word>(
107 handle: &Handle<T::Instance, state::Enabled>,
108 stream: T::Stream,
109 buffer: Pin<B>,
110 target: T,
111 address: u32,
112 direction: Direction,
113 ) -> Self
114 where
115 B: Deref,
116 B::Target: Buffer<Word>,
117 Word: SupportedWordSize,
118 {
119 assert!(buffer.len() <= u16::max_value() as usize);
120
121 let nr = T::Stream::number();
125
126 handle.dma.st[nr].cr.modify(|_, w| w.en().disabled());
128 while handle.dma.st[nr].cr.read().en().is_enabled() {}
129
130 T::Stream::clear_status_flags(&handle.dma);
131
132 handle.dma.st[nr].par.write(|w| w.pa().bits(address));
134
135 let memory_address = buffer.as_ptr() as u32;
137 handle.dma.st[nr]
138 .m0ar
139 .write(|w| w.m0a().bits(memory_address));
140
141 handle.dma.st[nr]
146 .ndtr
147 .write(|w| w.ndt().bits(buffer.len() as u16));
148
149 handle.dma.st[nr].fcr.modify(|_, w| {
151 w
152 .feie()
154 .disabled()
155 .dmdis()
157 .enabled()
158 });
159
160 handle.dma.st[nr].cr.write(|w| {
162 let w = T::Channel::select(w);
163
164 let w = match direction {
165 Direction::MemoryToPeripheral => w.dir().memory_to_peripheral(),
166 Direction::PeripheralToMemory => w.dir().peripheral_to_memory(),
167 };
168
169 w
170 .mburst()
172 .single()
173 .pburst()
174 .single()
175 .dbm()
177 .disabled()
178 .pl()
180 .very_high()
181 .msize()
183 .variant(Word::msize())
184 .psize()
186 .variant(Word::psize())
187 .minc()
189 .incremented()
190 .pinc()
192 .fixed()
193 .circ()
195 .disabled()
196 .pfctrl()
198 .dma()
199 .tcie()
201 .disabled()
202 .htie()
203 .disabled()
204 .teie()
205 .disabled()
206 .dmeie()
207 .disabled()
208 });
209
210 Transfer {
211 res: TransferResources {
212 stream,
213 buffer,
214 target,
215 },
216 _state: Ready,
217 }
218 }
219
220 pub fn enable_interrupts(
226 &mut self,
227 handle: &Handle<T::Instance, state::Enabled>,
228 interrupts: Interrupts,
229 ) {
230 handle.dma.st[T::Stream::number()].cr.modify(|_, w| {
231 let w = if interrupts.transfer_complete {
232 w.tcie().enabled()
233 } else {
234 w
235 };
236
237 let w = if interrupts.half_transfer {
238 w.htie().enabled()
239 } else {
240 w
241 };
242
243 let w = if interrupts.transfer_error {
244 w.teie().enabled()
245 } else {
246 w
247 };
248
249 let w = if interrupts.direct_mode_error {
250 w.dmeie().enabled()
251 } else {
252 w
253 };
254
255 w
256 });
257
258 unsafe { NVIC::unmask(T::INTERRUPT) };
260 }
261
262 pub fn start(self, handle: &Handle<T::Instance, state::Enabled>) -> Transfer<T, B, Started> {
267 T::Stream::clear_status_flags(&handle.dma);
268 atomic::fence(Ordering::SeqCst);
269
270 handle.dma.st[T::Stream::number()]
271 .cr
272 .modify(|_, w| w.en().enabled());
273
274 Transfer {
275 res: self.res,
276 _state: Started,
277 }
278 }
279}
280
281impl<T, B> Transfer<T, B, Started>
282where
283 T: Target,
284{
285 pub fn is_active(&self, handle: &Handle<T::Instance, state::Enabled>) -> bool {
287 handle.dma.st[T::Stream::number()]
288 .cr
289 .read()
290 .en()
291 .is_enabled()
292 }
293
294 pub fn cancel(&self, handle: &Handle<T::Instance, state::Enabled>) {
296 handle.dma.st[T::Stream::number()]
297 .cr
298 .write(|w| w.en().disabled());
299 }
300
301 pub fn wait(
312 self,
313 handle: &Handle<T::Instance, state::Enabled>,
314 ) -> Result<TransferResources<T, B>, (TransferResources<T, B>, Error)> {
315 NVIC::mask(T::INTERRUPT);
317
318 while self.is_active(handle) {
320 if let Err(error) = Error::check::<T::Stream>(&handle.dma) {
321 return Err((self.res, error));
322 }
323 }
324
325 atomic::fence(Ordering::SeqCst);
326
327 if let Err(error) = Error::check::<T::Stream>(&handle.dma) {
328 return Err((self.res, error));
329 }
330
331 Ok(self.res)
332 }
333}
334
335pub struct TransferResources<T: Target, B> {
337 pub stream: T::Stream,
338 pub buffer: Pin<B>,
339 pub target: T,
340}
341
342impl<T, B> fmt::Debug for TransferResources<T, B>
346where
347 T: Target,
348{
349 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
350 write!(f, "TransferResources {{ .. }}")
351 }
352}
353
354pub(crate) enum Direction {
355 MemoryToPeripheral,
356 PeripheralToMemory,
357}
358
359pub trait Target {
364 type Instance: Deref<Target = dma2::RegisterBlock>;
365 type Stream: Stream;
366 type Channel: Channel;
367
368 const INTERRUPT: Interrupt;
369}
370
371macro_rules! impl_target {
372 (
373 $(
374 $ty:ty,
375 $instance:ty,
376 $stream:ident,
377 $channel:ty,
378 $interrupt:ident;
379 )*
380 ) => {
381 $(
382 impl Target for $ty {
383 type Instance = $instance;
384 type Stream = $stream<$instance>;
385 type Channel = $channel;
386
387 const INTERRUPT: Interrupt = Interrupt::$interrupt;
388 }
389 )*
390 }
391}
392
393impl_target!(
403 spi::Rx<pac::SPI1>, DMA2, Stream0, Channel3, DMA2_STREAM0;
405 spi::Rx<pac::SPI2>, DMA1, Stream3, Channel0, DMA1_STREAM3;
407 spi::Rx<pac::SPI3>, DMA1, Stream0, Channel0, DMA1_STREAM0;
408 spi::Rx<pac::SPI4>, DMA2, Stream0, Channel4, DMA2_STREAM0;
410 spi::Rx<pac::SPI5>, DMA2, Stream3, Channel2, DMA2_STREAM3;
412 spi::Tx<pac::SPI1>, DMA2, Stream3, Channel3, DMA2_STREAM3;
416 spi::Tx<pac::SPI2>, DMA1, Stream4, Channel0, DMA1_STREAM4;
418 spi::Tx<pac::SPI3>, DMA1, Stream5, Channel0, DMA1_STREAM5;
419 spi::Tx<pac::SPI4>, DMA2, Stream1, Channel4, DMA2_STREAM1;
421 spi::Tx<pac::SPI5>, DMA2, Stream4, Channel2, DMA2_STREAM4;
423 serial::Rx<pac::USART1>, DMA2, Stream2, Channel4, DMA2_STREAM2;
427 serial::Rx<pac::USART2>, DMA1, Stream5, Channel4, DMA1_STREAM5;
429 serial::Rx<pac::USART3>, DMA1, Stream1, Channel4, DMA1_STREAM1;
430 serial::Rx<pac::UART4>, DMA1, Stream2, Channel4, DMA1_STREAM2;
431 serial::Rx<pac::UART5>, DMA1, Stream0, Channel4, DMA1_STREAM0;
432 serial::Rx<pac::USART6>, DMA2, Stream1, Channel5, DMA2_STREAM1;
433 serial::Rx<pac::UART7>, DMA1, Stream3, Channel5, DMA1_STREAM3;
435 serial::Rx<pac::UART8>, DMA1, Stream6, Channel5, DMA1_STREAM6;
436
437 serial::Tx<pac::USART1>, DMA2, Stream7, Channel4, DMA2_STREAM7;
439 serial::Tx<pac::USART2>, DMA1, Stream6, Channel4, DMA1_STREAM6;
440 serial::Tx<pac::USART3>, DMA1, Stream3, Channel4, DMA1_STREAM3;
441 serial::Tx<pac::UART4>, DMA1, Stream4, Channel4, DMA1_STREAM4;
443 serial::Tx<pac::UART5>, DMA1, Stream7, Channel4, DMA1_STREAM7;
444 serial::Tx<pac::USART6>, DMA2, Stream6, Channel5, DMA2_STREAM6;
445 serial::Tx<pac::UART7>, DMA1, Stream1, Channel5, DMA1_STREAM1;
447 serial::Tx<pac::UART8>, DMA1, Stream0, Channel5, DMA1_STREAM0;
448
449 qspi::RxTx<pac::QUADSPI>, DMA2, Stream7, Channel3, DMA2_STREAM7;
451);
452
453#[cfg(any(
454 feature = "stm32f745",
455 feature = "stm32f746",
456 feature = "stm32f756",
457 feature = "stm32f765",
458 feature = "stm32f767",
459 feature = "stm32f769",
460 feature = "stm32f777",
461 feature = "stm32f778",
462 feature = "stm32f779",
463))]
464impl_target!(
465 spi::Rx<pac::SPI6>, DMA2, Stream6, Channel1, DMA2_STREAM6;
466 spi::Tx<pac::SPI6>, DMA2, Stream5, Channel1, DMA2_STREAM5;
467);
468
469pub trait Stream {
474 fn number() -> usize;
475
476 fn clear_status_flags(dma: &dma2::RegisterBlock);
477
478 fn is_transfer_complete(dma: &dma2::RegisterBlock) -> bool;
479 fn is_half_transfer(dma: &dma2::RegisterBlock) -> bool;
480 fn is_transfer_error(dma: &dma2::RegisterBlock) -> bool;
481 fn is_direct_mode_error(dma: &dma2::RegisterBlock) -> bool;
482 fn is_fifo_error(dma: &dma2::RegisterBlock) -> bool;
483}
484
485macro_rules! impl_stream {
486 (
487 $(
488 $name:ident,
489 $name_lower:ident,
490 $number:expr,
491 $flag_reg:ident,
492 $feif:ident,
493 $dmeif:ident,
494 $teif:ident,
495 $htif:ident,
496 $tcif:ident,
497 $flag_clear_reg:ident,
498 ($($flag_clear_field:ident,)*);
499 )*
500 ) => {
501 pub struct Streams<I> {
502 $(pub $name_lower: $name<I>,)*
503 }
504
505 impl<I> Streams<I> {
506 fn new() -> Self {
507 Self {
508 $($name_lower: $name(PhantomData),)*
509 }
510 }
511 }
512
513
514 $(
515 pub struct $name<I>(PhantomData<I>);
516
517 impl<I> Stream for $name<I> {
518 fn number() -> usize { $number }
519
520 fn clear_status_flags(dma: &dma2::RegisterBlock) {
521 dma.$flag_clear_reg.write(|w|
522 w
523 $(.$flag_clear_field().clear())*
524 );
525 }
526
527 fn is_transfer_complete(dma: &dma2::RegisterBlock) -> bool {
528 dma.$flag_reg.read().$tcif().is_complete()
529 }
530 fn is_half_transfer(dma: &dma2::RegisterBlock) -> bool {
531 dma.$flag_reg.read().$htif().is_half()
532 }
533 fn is_transfer_error(dma: &dma2::RegisterBlock) -> bool {
534 dma.$flag_reg.read().$teif().is_error()
535 }
536 fn is_direct_mode_error(dma: &dma2::RegisterBlock) -> bool {
537 dma.$flag_reg.read().$dmeif().is_error()
538 }
539 fn is_fifo_error(dma: &dma2::RegisterBlock) -> bool {
540 dma.$flag_reg.read().$feif().is_error()
541 }
542 }
543 )*
544 }
545}
546
547impl_stream!(
548 Stream0, stream0, 0,
549 lisr, feif0, dmeif0, teif0, htif0, tcif0,
550 lifcr, (cfeif0, cdmeif0, cteif0, chtif0, ctcif0,);
551 Stream1, stream1, 1,
552 lisr, feif1, dmeif1, teif1, htif1, tcif1,
553 lifcr, (cfeif1, cdmeif1, cteif1, chtif1, ctcif1,);
554 Stream2, stream2, 2,
555 lisr, feif2, dmeif2, teif2, htif2, tcif2,
556 lifcr, (cfeif2, cdmeif2, cteif2, chtif2, ctcif2,);
557 Stream3, stream3, 3,
558 lisr, feif3, dmeif3, teif3, htif3, tcif3,
559 lifcr, (cfeif3, cdmeif3, cteif3, chtif3, ctcif3,);
560 Stream4, stream4, 4,
561 hisr, feif4, dmeif4, teif4, htif4, tcif4,
562 hifcr, (cfeif4, cdmeif4, cteif4, chtif4, ctcif4,);
563 Stream5, stream5, 5,
564 hisr, feif5, dmeif5, teif5, htif5, tcif5,
565 hifcr, (cfeif5, cdmeif5, cteif5, chtif5, ctcif5,);
566 Stream6, stream6, 6,
567 hisr, feif6, dmeif6, teif6, htif6, tcif6,
568 hifcr, (cfeif6, cdmeif6, cteif6, chtif6, ctcif6,);
569 Stream7, stream7, 7,
570 hisr, feif7, dmeif7, teif7, htif7, tcif7,
571 hifcr, (cfeif7, cdmeif7, cteif7, chtif7, ctcif7,);
572);
573
574pub trait Channel {
579 fn select(w: &mut dma2::st::cr::W) -> &mut dma2::st::cr::W;
580}
581
582macro_rules! impl_channel {
583 ($($name:ident, $number:expr;)*) => {
584 $(
585 pub struct $name;
586
587 impl Channel for $name {
588 fn select<'r>(w: &'r mut dma2::st::cr::W)
589 -> &'r mut dma2::st::cr::W
590 {
591 w.chsel().bits($number)
594 }
595 }
596 )*
597 }
598}
599
600impl_channel!(
601 Channel0, 0;
602 Channel1, 1;
603 Channel2, 2;
604 Channel3, 3;
605 Channel4, 4;
606 Channel5, 5;
607 Channel6, 6;
608 Channel7, 7;
609);
610
611pub trait Instance {}
616
617macro_rules! impl_instance {
618 ($($name:ty;)*) => {
619 $(
620 impl Instance for $name {
621 }
622 )*
623 }
624}
625
626impl_instance!(
627 DMA1;
628 DMA2;
629);
630
631#[derive(Clone, Copy)]
633pub struct Interrupts {
634 pub transfer_complete: bool,
635 pub half_transfer: bool,
636 pub transfer_error: bool,
637 pub direct_mode_error: bool,
638}
639
640impl Default for Interrupts {
641 fn default() -> Self {
642 Self {
643 transfer_complete: false,
644 half_transfer: false,
645 transfer_error: false,
646 direct_mode_error: false,
647 }
648 }
649}
650
651#[derive(Debug)]
653pub enum Error {
654 Transfer,
655 DirectMode,
656}
657
658impl Error {
659 pub(crate) fn check<S>(dma: &dma2::RegisterBlock) -> Result<(), Self>
660 where
661 S: Stream,
662 {
663 if S::is_transfer_error(dma) {
664 return Err(Error::Transfer);
665 }
666 if S::is_direct_mode_error(dma) {
667 return Err(Error::DirectMode);
668 }
669 Ok(())
674 }
675}
676
677pub struct Ready;
679
680pub struct Started;
682
683pub(crate) trait Buffer<Word> {
685 fn as_ptr(&self) -> *const Word;
686 fn len(&self) -> usize;
687}
688
689impl<T, Word> Buffer<Word> for T
690where
691 T: ?Sized + AsSlice<Element = Word>,
692{
693 fn as_ptr(&self) -> *const Word {
694 self.as_slice().as_ptr()
695 }
696
697 fn len(&self) -> usize {
698 self.as_slice().len()
699 }
700}
701
702pub(crate) struct PtrBuffer<Word: SupportedWordSize> {
706 pub ptr: *const Word,
707 pub len: usize,
708}
709
710impl<Word> Deref for PtrBuffer<Word>
713where
714 Word: SupportedWordSize,
715{
716 type Target = Self;
717
718 fn deref(&self) -> &Self::Target {
719 self
720 }
721}
722
723impl<Word> Buffer<Word> for PtrBuffer<Word>
724where
725 Word: SupportedWordSize,
726{
727 fn as_ptr(&self) -> *const Word {
728 self.ptr
729 }
730
731 fn len(&self) -> usize {
732 self.len
733 }
734}
735
736pub trait SupportedWordSize: private::Sealed + Unpin + 'static {
737 fn msize() -> cr::MSIZE_A;
738 fn psize() -> cr::PSIZE_A;
739}
740
741impl private::Sealed for u8 {}
742impl SupportedWordSize for u8 {
743 fn msize() -> cr::MSIZE_A {
744 cr::MSIZE_A::Bits8
745 }
746
747 fn psize() -> cr::PSIZE_A {
748 cr::MSIZE_A::Bits8
749 }
750}
751
752impl private::Sealed for u16 {}
753impl SupportedWordSize for u16 {
754 fn msize() -> cr::MSIZE_A {
755 cr::MSIZE_A::Bits16
756 }
757
758 fn psize() -> cr::PSIZE_A {
759 cr::MSIZE_A::Bits16
760 }
761}
762
763mod private {
764 pub trait Sealed {}
770}