stm32f3xx_hal/
dma.rs

1//! # Direct memory access (DMA) controller.
2//!
3//! Currently DMA is only supported for STM32F303 or STM32F302 MCUs.
4//!
5//! ## Examples
6//!
7//! An example how to use DMA for serial, can be found at [examples/serial_dma.rs]
8//!
9//! [examples/serial_dma.rs]: https://github.com/stm32-rs/stm32f3xx-hal/blob/v0.10.0/examples/serial_dma.rs
10
11// To learn about most of the ideas implemented here, check out the DMA section
12// of the Embedonomicon: https://docs.rust-embedded.org/embedonomicon/dma.html
13
14pub 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/// Extension trait to split a DMA peripheral into independent channels
31#[allow(clippy::module_name_repetitions)]
32pub trait DmaExt {
33    /// The type to split the DMA into
34    type Channels;
35
36    /// Split the DMA into independent channels
37    fn split(self, ahb: &mut AHB) -> Self::Channels;
38}
39
40/// Trait implemented by DMA targets.
41pub trait Target {
42    /// Enable DMA on the target
43    fn enable_dma(&mut self) {}
44    /// Disable DMA on the target
45    fn disable_dma(&mut self) {}
46}
47
48/// An in-progress one-shot DMA transfer
49#[derive(Debug)]
50#[cfg_attr(feature = "defmt", derive(defmt::Format))]
51pub struct Transfer<B, C: Channel, T: Target> {
52    // This is always a `Some` outside of `drop`.
53    inner: Option<TransferInner<B, C, T>>,
54}
55
56impl<B, C: Channel, T: Target> Transfer<B, C, T> {
57    /// Start a DMA write transfer.
58    ///
59    /// # Panics
60    ///
61    /// Panics if the buffer is longer than 65535 words.
62    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        // SAFETY: We don't know the concrete type of `buffer` here, all
68        // we can use are its `WriteBuffer` methods. Hence the only `&mut self`
69        // method we can call is `write_buffer`, which is allowed by
70        // `WriteBuffer`'s safety requirements.
71        let (ptr, len) = unsafe { buffer.write_buffer() };
72        let len = crate::expect!(u16::try_from(len).ok(), "buffer is too large");
73
74        // SAFETY: We are using the address of a 'static WriteBuffer here,
75        // which is guaranteed to be safe for DMA.
76        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        // SAFTEY: we take ownership of the buffer, which is 'static as well, so it lives long
82        // enough (at least longer that the DMA transfer itself)
83        #[allow(clippy::undocumented_unsafe_blocks)]
84        unsafe {
85            Self::start(buffer, channel, target)
86        }
87    }
88
89    /// Start a DMA read transfer.
90    ///
91    /// # Panics
92    ///
93    /// Panics if the buffer is longer than 65535 words.
94    pub fn start_read(buffer: B, mut channel: C, target: T) -> Self
95    where
96        B: ReadBuffer + 'static,
97        T: OnChannel<C>,
98    {
99        // SAFETY: We don't know the concrete type of `buffer` here, all
100        // we can use are its `ReadBuffer` methods. Hence there are no
101        // `&mut self` methods we can call, so we are safe according to
102        // `ReadBuffer`'s safety requirements.
103        let (ptr, len) = unsafe { buffer.read_buffer() };
104        let len = crate::expect!(u16::try_from(len).ok(), "buffer is too large");
105
106        // SAFETY: We are using the address of a 'static ReadBuffer here,
107        // which is guaranteed to be safe for DMA.
108        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        // SAFTEY: We take ownership of the buffer, which is 'static as well, so it lives long
114        // enough (at least longer that the DMA transfer itself)
115        #[allow(clippy::undocumented_unsafe_blocks)]
116        unsafe {
117            Self::start(buffer, channel, target)
118        }
119    }
120
121    /// # Safety
122    ///
123    /// Callers must ensure that:
124    ///
125    /// - the given buffer will be valid for the duration of the transfer
126    /// - the DMA channel is configured correctly for the given target and buffer
127    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    /// Is this transfer complete?
148    ///
149    /// # Panics
150    ///
151    /// Panics if no transfer is ongoing.
152    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    /// Stop this transfer and return ownership over its parts
158    ///
159    /// # Panics
160    ///
161    /// Panics no transfer is ongoing.
162    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    /// Block until this transfer is done and return ownership over its parts
170    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/// This only exists so we can implement `Drop` for `Transfer`.
186#[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    /// Stop this transfer
196    fn stop(&mut self) {
197        self.channel.disable();
198        self.target.disable_dma();
199
200        atomic::compiler_fence(Ordering::SeqCst);
201    }
202}
203
204/// DMA address increment mode
205#[derive(Debug, Copy, Clone, PartialEq, Eq)]
206#[cfg_attr(feature = "defmt", derive(defmt::Format))]
207pub enum Increment {
208    /// Enable increment
209    Enable,
210    /// Disable increment
211    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/// Channel priority level
224#[derive(Debug, Copy, Clone, PartialEq, Eq)]
225#[cfg_attr(feature = "defmt", derive(defmt::Format))]
226pub enum Priority {
227    /// Low
228    Low,
229    /// Medium
230    Medium,
231    /// High
232    High,
233    /// Very high
234    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/// DMA transfer direction
249#[derive(Debug, Copy, Clone, PartialEq, Eq)]
250#[cfg_attr(feature = "defmt", derive(defmt::Format))]
251pub enum Direction {
252    /// From memory to peripheral
253    FromMemory,
254    /// From peripheral to memory
255    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/// DMA events
268#[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    /// First half of a transfer is done
274    HalfTransfer,
275    /// Transfer is complete
276    TransferComplete,
277    /// A transfer error occurred
278    TransferError,
279    /// Any of the above events occurred
280    Any,
281}
282
283/// Trait implemented by all DMA channels
284pub trait Channel: private::Channel {
285    /// Is the interrupt flag for the given event set?
286    fn is_event_triggered(&self, event: Event) -> bool;
287
288    /// Clear the interrupt flag for the given event.
289    ///
290    /// Passing `Event::Any` clears all interrupt flags.
291    ///
292    /// Note that the the global interrupt flag is not automatically cleared
293    /// even when all other flags are cleared. The only way to clear it is to
294    /// call this method with `Event::Any`.
295    fn clear_event(&mut self, event: Event);
296
297    /// Clear **all** interrupt event flags
298    fn clear_events(&mut self) {
299        self.clear_event(Event::Any);
300    }
301
302    /// Reset the control registers of this channel.
303    /// This stops any ongoing transfers.
304    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    /// Set the base address of the peripheral data register from/to which the
313    /// data will be read/written.
314    ///
315    /// Only call this method on disabled channels.
316    ///
317    /// # Panics
318    ///
319    /// Panics if this channel is enabled.
320    ///
321    /// # Safety
322    ///
323    /// Callers must ensure the given address is the address of a peripheral
324    /// register that supports DMA.
325    unsafe fn set_peripheral_address(&mut self, address: u32, inc: Increment) {
326        crate::assert!(!self.is_enabled());
327
328        // SAFETY: If the caller does ensure, that address is valid address, this should be safe
329        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    /// Set the base address of the memory area from/to which
336    /// the data will be read/written.
337    ///
338    /// Only call this method on disabled channels.
339    ///
340    /// # Panics
341    ///
342    /// Panics if this channel is enabled.
343    ///
344    /// # Safety
345    ///
346    /// Callers must ensure the given address is a valid memory address
347    /// that will remain valid as long as at is used by DMA.
348    unsafe fn set_memory_address(&mut self, address: u32, inc: Increment) {
349        crate::assert!(!self.is_enabled());
350
351        // SAFETY: If the caller does ensure, that address is valid address, this should be safe
352        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    /// Set the number of words to transfer.
359    ///
360    /// Only call this method on disabled channels.
361    ///
362    /// # Panics
363    ///
364    /// Panics if this channel is enabled.
365    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    /// Set the word size.
372    ///
373    /// # Panics
374    ///
375    /// Panics if the word size is not one of 8, 16, or 32 bits.
376    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    /// Set the priority level of this channel
396    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    /// Set the transfer direction
402    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    /// Enable or disable the interrupt for the specified [`Event`].
408    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    /// Enable the interrupt for the given [`Event`].
422    fn enable_interrupt(&mut self, event: Event) {
423        self.configure_intterupt(event, true);
424    }
425
426    /// Disable the interrupt for the given [`Event`].
427    fn disable_interrupt(&mut self, event: Event) {
428        self.configure_intterupt(event, false);
429    }
430
431    /// Start a transfer
432    fn enable(&mut self) {
433        self.clear_event(Event::Any);
434        self.ch().cr.modify(|_, w| w.en().enabled());
435    }
436
437    /// Stop the current transfer
438    fn disable(&mut self) {
439        self.ch().cr.modify(|_, w| w.en().disabled());
440    }
441
442    /// Is there a transfer in progress on this channel?
443    fn is_enabled(&self) -> bool {
444        self.ch().cr.read().en().is_enabled()
445    }
446}
447
448mod private {
449    use crate::pac;
450
451    /// Channel methods private to this module
452    pub trait Channel {
453        /// Return the register block for this channel
454        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                /// DMA channels
492                #[derive(Debug)]
493                #[cfg_attr(feature = "defmt", derive(defmt::Format))]
494                pub struct Channels {
495                    $(
496                        /// Channel
497                        pub $chi: $Ci,
498                    )+
499                }
500
501                impl Channels {
502                    /// Reset the control registers of all channels.
503                    /// This stops any ongoing transfers.
504                    fn reset(&mut self) {
505                        $( self.$chi.reset(); )+
506                    }
507                }
508
509                $(
510                    /// Singleton that represents a DMA channel
511                    #[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                            // SAFETY: $Ci grants exclusive access to this register
520                            unsafe { &(*$DMAx::ptr()).$chi }
521                        }
522                    }
523
524                    impl Channel for $Ci {
525                        fn is_event_triggered(&self, event: Event) -> bool {
526                            // SAFETY: atomic read
527                            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                            // SAFETY: atomic write to a stateless register
538                            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
583/// Marker trait mapping DMA targets to their channels
584pub 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
602// See mapping details in RM0316 13.4.7 Fig 47 onwards
603on_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);