stm32f429_hal/
dma.rs

1//! DMA abstractions
2
3use core::mem::size_of;
4use core::ops::Not;
5use rcc::AHB1;
6
7/// DMA channel, implemented by the types `C0`, `C1`, `C2`, …
8pub trait DmaChannel {
9    /// Numeric channel number
10    fn channel() -> u8;
11}
12
13/// DMA channel
14pub struct C0;
15impl DmaChannel for C0 {
16    fn channel() -> u8 { 0 }
17}
18/// DMA channel
19pub struct C1;
20impl DmaChannel for C1 {
21    fn channel() -> u8 { 1 }
22}
23/// DMA channel
24pub struct C2;
25impl DmaChannel for C2 {
26    fn channel() -> u8 { 2 }
27}
28/// DMA channel
29pub struct C3;
30impl DmaChannel for C3 {
31    fn channel() -> u8 { 3 }
32}
33/// DMA channel
34pub struct C4;
35impl DmaChannel for C4 {
36    fn channel() -> u8 { 4 }
37}
38/// DMA channel
39pub struct C5;
40impl DmaChannel for C5 {
41    fn channel() -> u8 { 5 }
42}
43/// DMA channel
44pub struct C6;
45impl DmaChannel for C6 {
46    fn channel() -> u8 { 6 }
47}
48/// DMA channel
49pub struct C7;
50impl DmaChannel for C7 {
51    fn channel() -> u8 { 7 }
52}
53
54/// Split the DMA device into separate streams.
55pub trait DmaExt {
56    /// Target type
57    type Streams;
58
59    /// Split into separate streams.
60    fn split(self, ahb: &mut AHB1) -> Self::Streams;
61}
62
63/// Events to enable interrupts for.
64pub enum Event {
65    /// Half transfer
66    HalfTransfer,
67    /// Transfer complete
68    TransferComplete,
69}
70
71#[derive(Debug, Clone, Copy)]
72enum DoubleBuffer {
73    Memory0 = 0,
74    Memory1 = 1,
75}
76
77impl Not for DoubleBuffer {
78    type Output = Self;
79    fn not(self) -> Self::Output {
80        match self {
81            DoubleBuffer::Memory0 =>
82                DoubleBuffer::Memory1,
83            DoubleBuffer::Memory1 =>
84                DoubleBuffer::Memory0,
85        }
86    }
87}
88
89/// DMA stream peripheral
90pub trait DmaStream {
91    /// Enable interrupt
92    fn listen(&mut self, event: Event);
93    /// Disable interrupt
94    fn unlisten(&mut self, event: Event);
95
96    /// Transfer is complete?
97    fn is_complete(&self) -> bool;
98    /// Transfer has error?
99    fn has_error(&self) -> bool;
100    /// Reset after a transfer
101    fn reset(&mut self);
102}
103
104/// DMA stream that can start DMA transfer `X`
105pub trait DmaStreamTransfer<S, T, X: Transfer<Self>>: DmaStream + Sized {
106    /// Start DMA transfer
107    fn start_transfer<CHANNEL: DmaChannel>(self, source: S, target: &mut T) -> X;
108}
109
110/// DMA transfer
111pub trait Transfer<STREAM>: Sized {
112    /// Transfer is complete?
113    fn is_complete(&self) -> bool;
114    /// Transfer has error?
115    fn has_error(&self) -> bool;
116    /// Reset after a transfer
117    ///
118    /// Consumes the finished transfer and returns the stream.
119    fn reset(self) -> STREAM;
120
121    /// Wait until transfer is either complete or has error.
122    fn wait(self) -> Result<STREAM, STREAM> {
123        while !self.is_complete() && !self.has_error() {}
124        if self.is_complete() {
125            Ok(self.reset())
126        } else {
127            Err(self.reset())
128        }
129    }
130}
131
132
133macro_rules! dma {
134    ($($DMAX:ident: ($dmaX:ident, $dmaXen:ident, $dmaXrst:ident, {
135        $($SX:ident: (
136            $sx:ident,
137            $crX:ident: $CRX:ident,
138            $ndtrX:ident: $NDTRX:ident,
139            $parX:ident: $PARX:ident,
140            $m0arX:ident: $M0ARX:ident,
141            $m1arX:ident: $M1ARX:ident,
142            $isr:ident: $ISR:ident,
143            $ifcr:ident: $IFCR:ident,
144            $tcif:ident, $teif:ident,
145            $ctcif:ident, $cteif:ident,
146        ),)+
147    }),)+) => {
148        $(
149            /// Peripheral abstraction for DMA
150            pub mod $dmaX {
151                use stm32f429::{$DMAX, dma2};
152
153                use rcc::AHB1;
154                use dma::{DmaExt, DmaStream, DmaStreamTransfer, DmaChannel,
155                          Event, data_size};
156
157                /// The numbered DMA streams of a device that you can
158                /// use separately.
159                #[derive(Debug)]
160                pub struct Streams {
161                    $(
162                        /// DMA stream `$sx`
163                        pub $sx: $SX
164                    ),+
165                }
166
167                $(
168                    /// A handle to the `$SX` DMA peripheral
169                    #[derive(Debug)]
170                    pub struct $SX { _0: () }
171
172                    impl $SX {
173                        fn isr(&self) -> dma2::$isr::R {
174                            // NOTE(unsafe) atomic read with no side effects
175                            unsafe { (*$DMAX::ptr()).$isr.read() }
176                        }
177
178                        fn ifcr(&self) -> &dma2::$IFCR {
179                            unsafe { &(*$DMAX::ptr()).$ifcr }
180                        }
181
182                        fn cr(&mut self) -> &dma2::$CRX {
183                            unsafe { &(*$DMAX::ptr()).$crX }
184                        }
185
186                        fn ndtr(&mut self) -> &dma2::$NDTRX {
187                            unsafe { &(*$DMAX::ptr()).$ndtrX }
188                        }
189
190                        // fn get_ndtr(&self) -> u32 {
191                        //     // NOTE(unsafe) atomic read with no side effects
192                        //     unsafe { (*$DMAX::ptr()).$ndtrX.read().bits() }
193                        // }
194
195                        fn par(&mut self) -> &dma2::$PARX {
196                            unsafe { &(*$DMAX::ptr()).$parX }
197                        }
198
199                        fn m0ar(&mut self) -> &dma2::$M0ARX {
200                            unsafe { &(*$DMAX::ptr()).$m0arX }
201                        }
202
203                        fn m1ar(&mut self) -> &dma2::$M1ARX {
204                            unsafe { &(*$DMAX::ptr()).$m1arX }
205                        }
206                    }
207
208                    impl DmaStream for $SX {
209                        fn listen(&mut self, event: Event) {
210                            match event {
211                                Event::HalfTransfer => self.cr().modify(|_, w| w.htie().set_bit()),
212                                Event::TransferComplete => {
213                                    self.cr().modify(|_, w| w.tcie().set_bit())
214                                }
215                            }
216                        }
217
218                        fn unlisten(&mut self, event: Event) {
219                            match event {
220                                Event::HalfTransfer => {
221                                    self.cr().modify(|_, w| w.htie().clear_bit())
222                                },
223                                Event::TransferComplete => {
224                                    self.cr().modify(|_, w| w.tcie().clear_bit())
225                                }
226                            }
227                        }
228
229                        fn is_complete(&self) -> bool {
230                            self.isr().$tcif().bit()
231                        }
232
233                        fn has_error(&self) -> bool {
234                            self.isr().$teif().bit()
235                        }
236
237                        fn reset(&mut self) {
238                            // Disable Stream
239                            self.cr().modify(|_, w| w.en().clear_bit());
240                            
241                            // Clear status bits
242                            self.ifcr().modify(|_, w| {
243                                w.$ctcif().set_bit()
244                                    .$cteif().set_bit()
245                            });
246                        }
247                    }
248                    
249                    impl<'s, S> DmaStreamTransfer<(&'s [S], &'s [S]), S, $sx::DoubleBufferedTransfer<S>> for $SX {
250                        /// Configure, enable, and return a double-buffered DMA transfer.
251                        fn start_transfer<CHANNEL: DmaChannel>(mut self, (source0, source1): (&'s [S], &'s [S]), target: &mut S) -> $sx::DoubleBufferedTransfer<S> {
252                            assert_eq!(source0.len(), source1.len());
253
254                            self.cr().modify(|_, w| unsafe {
255                                w.msize().bits(data_size::<S>())
256                                    .minc().set_bit()
257                                    .psize().bits(data_size::<S>())
258                                    .pinc().clear_bit()
259                                    .dbm().set_bit()
260                                    .ct().clear_bit()
261                                    .circ().set_bit()
262                                // Memory to peripheral
263                                    .dir().bits(0b01)
264                                    .chsel().bits(CHANNEL::channel())
265                            });
266
267                            let source0_addr = &source0[0] as *const _ as u32;
268                            self.m0ar().write(|w| unsafe { w.bits(source0_addr) });
269                            let source1_addr = &source1[0] as *const _ as u32;
270                            self.m1ar().write(|w| unsafe { w.bits(source1_addr) });
271                            let source_len = source0.len() as u32;
272                            self.ndtr().write(|w| unsafe { w.bits(source_len) });
273                            let target_addr = target as *const _ as u32;
274                            self.par().write(|w| unsafe { w.bits(target_addr) });
275
276                            // Enable Stream
277                            self.cr().modify(|_, w| w.en().set_bit());
278
279                            $sx::DoubleBufferedTransfer::new(self)
280                        }
281                    }
282
283                    impl<T, S: AsRef<[T]>> DmaStreamTransfer<S, T, $sx::OneShotTransfer<S>> for $SX {
284                        /// Configure, enable, and return a double-buffered DMA transfer.
285                        fn start_transfer<CHANNEL: DmaChannel>(mut self, source: S, target: &mut T) -> $sx::OneShotTransfer<S> {
286                            self.cr().modify(|_, w| unsafe {
287                                w.msize().bits(data_size::<T>())
288                                    .minc().set_bit()
289                                    .psize().bits(data_size::<T>())
290                                    .pinc().clear_bit()
291                                    .dbm().clear_bit()
292                                    .ct().clear_bit()
293                                    .circ().clear_bit()
294                                    // Memory to peripheral
295                                    .dir().bits(0b01)
296                                    .chsel().bits(CHANNEL::channel())
297                            });
298
299                            let source_addr = source.as_ref() as *const _ as *const () as u32;
300                            self.m0ar().write(|w| unsafe { w.bits(source_addr) });
301                            let source_len = source.as_ref().len() as u32;
302                            self.ndtr().write(|w| unsafe { w.bits(source_len) });
303                            let target_addr = target as *const _ as u32;
304                            self.par().write(|w| unsafe { w.bits(target_addr) });
305
306                            // Enable Stream
307                            self.cr().modify(|_, w| w.en().set_bit());
308
309                            $sx::OneShotTransfer::new(self, source)
310                        }
311                    }
312
313                    /// Contains the `DoubleBufferedTransfer` and the `OneShotTransfer` for `$SX`
314                    pub mod $sx {
315                        use core::marker::PhantomData;
316                        use dma::{DmaStream, Transfer, DoubleBuffer};
317                        use super::$SX;
318
319                        /// Double-buffered DMA transfer
320                        pub struct DoubleBufferedTransfer<S> {
321                            /// So that `poll()` can detect a buffer switch
322                            sent: [bool; 2],
323                            _source_el: PhantomData<S>,
324                            stream: $SX,
325                        }
326
327                        impl<S> Transfer<$SX> for DoubleBufferedTransfer<S> {
328                            fn is_complete(&self) -> bool {
329                                self.stream.is_complete()
330                            }
331
332                            fn has_error(&self) -> bool {
333                                self.stream.has_error()
334                            }
335
336                            fn reset(mut self) -> $SX {
337                                self.stream.reset();
338                                self.stream
339                            }
340                        }
341
342                        impl<S> DoubleBufferedTransfer<S> {
343                            /// Construct a new DMA transfer state,
344                            /// returned by `start_transfer` which
345                            /// configures and enables the stream
346                            /// before.
347                            pub fn new<'s>(stream: $SX) -> Self {
348                                Self {
349                                    sent: [false; 2],
350                                    _source_el: PhantomData,
351                                    stream,
352                                }
353                            }
354
355                            /// Return the index of the buffer currently being sent
356                            #[inline]
357                            fn front_buffer(&mut self) -> DoubleBuffer {
358                                if self.stream.cr().read().ct().bit() {
359                                    DoubleBuffer::Memory1
360                                } else {
361                                    DoubleBuffer::Memory0
362                                }
363                            }
364
365                            /// Return the index of the buffer **not** currently being sent
366                            #[inline]
367                            fn back_buffer(&mut self) -> DoubleBuffer {
368                                ! self.front_buffer()
369                            }
370
371                            /// Has the back buffer been sent?
372                            ///
373                            /// As this is used for polling, the
374                            /// function updates the `sent` status of
375                            /// the front buffer.
376                            pub fn writable(&mut self) -> bool {
377                                // Mark front buffer as being sent
378                                self.sent[self.front_buffer() as usize] = true;
379
380                                self.sent[self.back_buffer() as usize]
381                            }
382
383                            /// Update the back buffer.
384                            pub fn write<'s>(&mut self, source: &'s [S]) -> Result<(), ()> {
385                                if self.has_error() {
386                                    return Err(())
387                                }
388
389                                let source_addr = &source[0] as *const _ as u32;
390                                let bb = self.back_buffer();
391                                match bb {
392                                    DoubleBuffer::Memory0 =>
393                                        self.stream.m0ar().write(|w| unsafe { w.bits(source_addr) }),
394                                    DoubleBuffer::Memory1 =>
395                                        self.stream.m1ar().write(|w| unsafe { w.bits(source_addr) }),
396                                }
397                                // Let `writable()` mark it when it becomes the `front_buffer()`
398                                self.sent[bb as usize] = false;
399
400                                Ok(())
401                            }
402                        }
403
404                        /// One-shot DMA transfer
405                        pub struct OneShotTransfer<S> {
406                            source: S,
407                            stream: $SX,
408                        }
409
410                        impl<S> Transfer<$SX> for OneShotTransfer<S> {
411                            fn is_complete(&self) -> bool {
412                                self.stream.is_complete()
413                            }
414
415                            fn has_error(&self) -> bool {
416                                self.stream.has_error()
417                            }
418
419                            fn reset(mut self) -> $SX {
420                                drop(self.source);
421                                self.stream.reset();
422                                self.stream
423                            }
424                        }
425
426                        impl<S> OneShotTransfer<S> {
427                            /// Construct a new DMA transfer state,
428                            /// returned by `start_transfer` which
429                            /// configures and enables the stream
430                            /// before.
431                            pub fn new<'s>(stream: $SX, source: S) -> Self {
432                                Self {
433                                    source,
434                                    stream,
435                                }
436                            }
437
438                            /// debug
439                            pub fn status(&mut self) -> u32 {
440                                self.stream.cr().read().bits()
441                            }
442                        }
443                    }
444                )+
445
446                impl DmaExt for $DMAX {
447                    type Streams = Streams;
448
449                    fn split(self, ahb: &mut AHB1) -> Streams {
450                        ahb.enr().modify(|_, w| w.$dmaXen().set_bit());
451                        ahb.rstr().modify(|_, w| w.$dmaXrst().set_bit());
452                        ahb.rstr().modify(|_, w| w.$dmaXrst().clear_bit());
453
454                        // reset the DMA control registers (stops all on-going transfers)
455                        $(
456                            self.$crX.reset();
457                        )+
458
459                            Streams {
460                                $($sx: $SX { _0: () }),+
461                            }
462                    }
463                }
464            }
465        )+
466    }
467}
468
469dma! {
470    DMA1: (dma1, dma1en, dma1rst, {
471        S0: (
472            s0,
473            s0cr: S0CR,
474            s0ndtr: S0NDTR,
475            s0par: S0PAR,
476            s0m0ar: S0M0AR,
477            s0m1ar: S0M1AR,
478            lisr: LISR,
479            lifcr: LIFCR,
480            tcif0, teif0,
481            ctcif0, cteif0,
482        ),
483        S1: (
484            s1,
485            s1cr: S1CR,
486            s1ndtr: S1NDTR,
487            s1par: S1PAR,
488            s1m0ar: S1M0AR,
489            s1m1ar: S1M1AR,
490            lisr: LISR,
491            lifcr: LIFCR,
492            tcif1, teif1,
493            ctcif1, cteif1,
494        ),
495        S2: (
496            s2,
497            s2cr: S2CR,
498            s2ndtr: S2NDTR,
499            s2par: S2PAR,
500            s2m0ar: S2M0AR,
501            s2m1ar: S2M1AR,
502            lisr: LISR,
503            lifcr: LIFCR,
504            tcif2, teif2,
505            ctcif2, cteif2,
506        ),
507        S3: (
508            s3,
509            s3cr: S3CR,
510            s3ndtr: S3NDTR,
511            s3par: S3PAR,
512            s3m0ar: S3M0AR,
513            s3m1ar: S3M1AR,
514            lisr: LISR,
515            lifcr: LIFCR,
516            tcif3, teif3,
517            ctcif3, cteif3,
518        ),
519        S4: (
520            s4,
521            s4cr: S4CR,
522            s4ndtr: S4NDTR,
523            s4par: S4PAR,
524            s4m0ar: S4M0AR,
525            s4m1ar: S4M1AR,
526            hisr: HISR,
527            hifcr: HIFCR,
528            tcif4, teif4,
529            ctcif4, cteif4,
530        ),
531        S5: (
532            s5,
533            s5cr: S5CR,
534            s5ndtr: S5NDTR,
535            s5par: S5PAR,
536            s5m0ar: S5M0AR,
537            s5m1ar: S5M1AR,
538            hisr: HISR,
539            hifcr: HIFCR,
540            tcif5, teif5,
541            ctcif5, cteif5,
542        ),
543        S6: (
544            s6,
545            s6cr: S6CR,
546            s6ndtr: S6NDTR,
547            s6par: S6PAR,
548            s6m0ar: S6M0AR,
549            s6m1ar: S6M1AR,
550            hisr: HISR,
551            hifcr: HIFCR,
552            tcif6, teif6,
553            ctcif6, cteif6,
554        ),
555        S7: (
556            s7,
557            s7cr: S7CR,
558            s7ndtr: S7NDTR,
559            s7par: S7PAR,
560            s7m0ar: S7M0AR,
561            s7m1ar: S7M1AR,
562            hisr: HISR,
563            hifcr: HIFCR,
564            tcif7, teif7,
565            ctcif7, cteif7,
566        ),
567    }),
568    DMA2: (dma2, dma2en, dma2rst, {
569        S0: (
570            s0,
571            s0cr: S0CR,
572            s0ndtr: S0NDTR,
573            s0par: S0PAR,
574            s0m0ar: S0M0AR,
575            s0m1ar: S0M1AR,
576            lisr: LISR,
577            lifcr: LIFCR,
578            tcif0, teif0,
579            ctcif0, cteif0,
580        ),
581        S1: (
582            s1,
583            s1cr: S1CR,
584            s1ndtr: S1NDTR,
585            s1par: S1PAR,
586            s1m0ar: S1M0AR,
587            s1m1ar: S1M1AR,
588            lisr: LISR,
589            lifcr: LIFCR,
590            tcif1, teif1,
591            ctcif1, cteif1,
592        ),
593        S2: (
594            s2,
595            s2cr: S2CR,
596            s2ndtr: S2NDTR,
597            s2par: S2PAR,
598            s2m0ar: S2M0AR,
599            s2m1ar: S2M1AR,
600            lisr: LISR,
601            lifcr: LIFCR,
602            tcif2, teif2,
603            ctcif2, cteif2,
604        ),
605        S3: (
606            s3,
607            s3cr: S3CR,
608            s3ndtr: S3NDTR,
609            s3par: S3PAR,
610            s3m0ar: S3M0AR,
611            s3m1ar: S3M1AR,
612            lisr: LISR,
613            lifcr: LIFCR,
614            tcif3, teif3,
615            ctcif3, cteif3,
616        ),
617        S4: (
618            s4,
619            s4cr: S4CR,
620            s4ndtr: S4NDTR,
621            s4par: S4PAR,
622            s4m0ar: S4M0AR,
623            s4m1ar: S4M1AR,
624            hisr: HISR,
625            hifcr: HIFCR,
626            tcif4, teif4,
627            ctcif4, cteif4,
628        ),
629        S5: (
630            s5,
631            s5cr: S5CR,
632            s5ndtr: S5NDTR,
633            s5par: S5PAR,
634            s5m0ar: S5M0AR,
635            s5m1ar: S5M1AR,
636            hisr: HISR,
637            hifcr: HIFCR,
638            tcif5, teif5,
639            ctcif5, cteif5,
640        ),
641        S6: (
642            s6,
643            s6cr: S6CR,
644            s6ndtr: S6NDTR,
645            s6par: S6PAR,
646            s6m0ar: S6M0AR,
647            s6m1ar: S6M1AR,
648            hisr: HISR,
649            hifcr: HIFCR,
650            tcif6, teif6,
651            ctcif6, cteif6,
652        ),
653        S7: (
654            s7,
655            s7cr: S7CR,
656            s7ndtr: S7NDTR,
657            s7par: S7PAR,
658            s7m0ar: S7M0AR,
659            s7m1ar: S7M1AR,
660            hisr: HISR,
661            hifcr: HIFCR,
662            tcif7, teif7,
663            ctcif7, cteif7,
664        ),
665    }),
666}
667
668fn data_size<T>() -> u8 {
669    match size_of::<T>() {
670        1 => 0b00,
671        2 => 0b01,
672        4 => 0b10,
673        _ => panic!("No such data size"),
674    }
675}