stm32g0xx_hal/
dma.rs

1//! Direct Memory Access Engine
2use crate::dmamux::DmaMuxIndex;
3use crate::rcc::Rcc;
4use crate::stm32::DMAMUX;
5
6/// Extension trait to split a DMA peripheral into independent channels
7pub trait DmaExt {
8    /// The type to split the DMA into
9    type Channels;
10
11    /// Reset the DMA peripheral
12    fn reset(self, rcc: &mut Rcc) -> Self;
13
14    /// Split the DMA into independent channels
15    fn split(self, rcc: &mut Rcc, dmamux: DMAMUX) -> Self::Channels;
16}
17
18/// Channel priority level
19pub enum Priority {
20    /// Low
21    Low = 0b00,
22    /// Medium
23    Medium = 0b01,
24    /// High
25    High = 0b10,
26    /// Very high
27    VeryHigh = 0b11,
28}
29
30impl From<Priority> for u8 {
31    fn from(prio: Priority) -> Self {
32        match prio {
33            Priority::Low => 0b00,
34            Priority::Medium => 0b01,
35            Priority::High => 0b10,
36            Priority::VeryHigh => 0b11,
37        }
38    }
39}
40
41/// DMA transfer direction
42pub enum Direction {
43    /// From memory to peripheral
44    FromMemory,
45    /// From peripheral to memory
46    FromPeripheral,
47}
48
49impl From<Direction> for bool {
50    fn from(dir: Direction) -> Self {
51        match dir {
52            Direction::FromMemory => true,
53            Direction::FromPeripheral => false,
54        }
55    }
56}
57
58#[doc = "Peripheral size"]
59#[derive(Clone, Copy, Debug, Eq, PartialEq)]
60#[repr(u8)]
61pub enum WordSize {
62    #[doc = "0: 8-bit size"]
63    BITS8 = 0,
64    #[doc = "1: 16-bit size"]
65    BITS16 = 1,
66    #[doc = "2: 32-bit size"]
67    BITS32 = 2,
68}
69impl From<WordSize> for u8 {
70    #[inline(always)]
71    fn from(variant: WordSize) -> Self {
72        variant as _
73    }
74}
75
76/// DMA events
77pub enum Event {
78    /// First half of a transfer is done
79    HalfTransfer,
80    /// Transfer is complete
81    TransferComplete,
82    /// A transfer error occurred
83    TransferError,
84    /// Any of the above events occurred
85    Any,
86}
87
88mod private {
89    use crate::stm32;
90
91    /// Channel methods private to this module
92    pub trait Channel {
93        /// Return the register block for this channel
94        fn ch(&self) -> &stm32::dma::CH;
95    }
96}
97
98/// Trait implemented by all DMA channels
99pub trait Channel: private::Channel {
100    /// Connects the DMAMUX channel to the peripheral corresponding to index
101    fn select_peripheral(&mut self, index: DmaMuxIndex);
102
103    /// Is the interrupt flag for the given event set?
104    fn event_occurred(&self, event: Event) -> bool;
105
106    /// Clear the interrupt flag for the given event.
107    ///
108    /// Passing `Event::Any` clears all interrupt flags.
109    ///
110    /// Note that the the global interrupt flag is not automatically cleared
111    /// even when all other flags are cleared. The only way to clear it is to
112    /// call this method with `Event::Any`.
113    fn clear_event(&mut self, event: Event);
114
115    /// Reset the control registers of this channel.
116    /// This stops any ongoing transfers.
117    fn reset(&mut self) {
118        self.ch().cr.reset();
119        self.ch().ndtr.reset();
120        self.ch().par.reset();
121        self.ch().mar.reset();
122        self.clear_event(Event::Any);
123    }
124
125    /// Set the base address of the peripheral data register from/to which the
126    /// data will be read/written.
127    ///
128    /// Only call this method on disabled channels.
129    ///
130    /// # Panics
131    ///
132    /// Panics if this channel is enabled.
133    fn set_peripheral_address(&mut self, address: u32, inc: bool) {
134        assert!(!self.is_enabled());
135
136        self.ch().par.write(|w| unsafe { w.pa().bits(address) });
137        self.ch().cr.modify(|_, w| w.pinc().bit(inc));
138    }
139
140    /// Set the base address of the memory area from/to which
141    /// the data will be read/written.
142    ///
143    /// Only call this method on disabled channels.
144    ///
145    /// # Panics
146    ///
147    /// Panics if this channel is enabled.
148    fn set_memory_address(&mut self, address: u32, inc: bool) {
149        assert!(!self.is_enabled());
150
151        self.ch().mar.write(|w| unsafe { w.ma().bits(address) });
152        self.ch().cr.modify(|_, w| w.minc().bit(inc));
153    }
154
155    /// Set the number of words to transfer.
156    ///
157    /// Only call this method on disabled channels.
158    ///
159    /// # Panics
160    ///
161    /// Panics if this channel is enabled.
162    fn set_transfer_length(&mut self, len: u16) {
163        assert!(!self.is_enabled());
164
165        self.ch().ndtr.write(|w| unsafe { w.ndt().bits(len) });
166    }
167
168    /// Set the word size.
169    fn set_word_size(&mut self, wsize: WordSize) {
170        self.ch().cr.modify(|_, w| unsafe {
171            w.psize().bits(wsize as u8);
172            w.msize().bits(wsize as u8)
173        });
174    }
175
176    /// Set the priority level of this channel
177    fn set_priority_level(&mut self, priority: Priority) {
178        let pl = priority.into();
179        self.ch().cr.modify(|_, w| unsafe { w.pl().bits(pl) });
180    }
181
182    /// Set the transfer direction
183    fn set_direction(&mut self, direction: Direction) {
184        let dir = direction.into();
185        self.ch().cr.modify(|_, w| w.dir().bit(dir));
186    }
187
188    /// Set the circular mode of this channel
189    fn set_circular_mode(&mut self, circular: bool) {
190        self.ch().cr.modify(|_, w| w.circ().bit(circular));
191    }
192
193    /// Enable the interrupt for the given event
194    fn listen(&mut self, event: Event) {
195        use Event::*;
196        match event {
197            HalfTransfer => self.ch().cr.modify(|_, w| w.htie().set_bit()),
198            TransferComplete => self.ch().cr.modify(|_, w| w.tcie().set_bit()),
199            TransferError => self.ch().cr.modify(|_, w| w.teie().set_bit()),
200            Any => self.ch().cr.modify(|_, w| {
201                w.htie().set_bit();
202                w.tcie().set_bit();
203                w.teie().set_bit()
204            }),
205        }
206    }
207
208    /// Disable the interrupt for the given event
209    fn unlisten(&mut self, event: Event) {
210        use Event::*;
211        match event {
212            HalfTransfer => self.ch().cr.modify(|_, w| w.htie().clear_bit()),
213            TransferComplete => self.ch().cr.modify(|_, w| w.tcie().clear_bit()),
214            TransferError => self.ch().cr.modify(|_, w| w.teie().clear_bit()),
215            Any => self.ch().cr.modify(|_, w| {
216                w.htie().clear_bit();
217                w.tcie().clear_bit();
218                w.teie().clear_bit()
219            }),
220        }
221    }
222
223    /// Start a transfer
224    fn enable(&mut self) {
225        self.clear_event(Event::Any);
226        self.ch().cr.modify(|_, w| w.en().set_bit());
227    }
228
229    /// Stop the current transfer
230    fn disable(&mut self) {
231        self.ch().cr.modify(|_, w| w.en().clear_bit());
232    }
233
234    /// Is there a transfer in progress on this channel?
235    fn is_enabled(&self) -> bool {
236        self.ch().cr.read().en().bit_is_set()
237    }
238}
239
240// TODO: Blocked by https://github.com/stm32-rs/stm32-rs/pull/695
241#[cfg(any(feature = "stm32g030", feature = "stm32g031", feature = "stm32g041"))]
242macro_rules! dma {
243    (
244        channels: {
245            $( $Ci:ident: (
246                $chi:ident,
247                $htifi:ident, $tcifi:ident, $teifi:ident, $gifi:ident,
248                $chtifi:ident, $ctcifi:ident, $cteifi:ident, $cgifi:ident,
249                $MuxCi: ident
250            ), )+
251        },
252    ) => {
253        use crate::dmamux;
254        use crate::rcc::{Enable, Reset};
255        use crate::stm32::{self, DMA};
256
257        use crate::dmamux::DmaMuxExt;
258
259        /// DMA channels
260        pub struct Channels {
261            $( pub $chi: $Ci, )+
262        }
263
264        impl Channels {
265            /// Reset the control registers of all channels.
266            /// This stops any ongoing transfers.
267            fn reset(&mut self) {
268                $( self.$chi.reset(); )+
269            }
270        }
271
272
273        $(
274            /// Singleton that represents a DMA channel
275            pub struct $Ci {
276                mux: dmamux::$MuxCi,
277            }
278
279            impl private::Channel for $Ci {
280                fn ch(&self) -> &stm32::dma::CH {
281                    // NOTE(unsafe) $Ci grants exclusive access to this register
282                    unsafe { &(*DMA::ptr()).$chi }
283                }
284            }
285
286            impl $Ci {
287                pub fn mux(&mut self) -> &mut dyn dmamux::DmaMuxChannel {
288                    &mut self.mux
289                }
290            }
291
292            impl Channel for $Ci {
293
294                fn select_peripheral(&mut self, index: DmaMuxIndex) {
295                    self.mux().select_peripheral(index);
296                }
297
298                fn event_occurred(&self, event: Event) -> bool {
299                    use Event::*;
300
301                    // NOTE(unsafe) atomic read
302                    let flags = unsafe { (*DMA::ptr()).isr.read() };
303                    match event {
304                        HalfTransfer => flags.$htifi().bit_is_set(),
305                        TransferComplete => flags.$tcifi().bit_is_set(),
306                        TransferError => flags.$teifi().bit_is_set(),
307                        Any => flags.$gifi().bit_is_set(),
308                    }
309                }
310
311                fn clear_event(&mut self, event: Event) {
312                    use Event::*;
313
314                    // NOTE(unsafe) atomic write to a stateless register
315                    unsafe {
316                        let _ = &(*DMA::ptr()).ifcr.write(|w| match event {
317                            HalfTransfer => w.$chtifi().set_bit(),
318                            TransferComplete => w.$ctcifi().set_bit(),
319                            TransferError => w.$cteifi().set_bit(),
320                            Any => w.$cgifi().set_bit(),
321                        });
322                    }
323                }
324
325            }
326        )+
327    }
328}
329
330// TODO: Blocked by https://github.com/stm32-rs/stm32-rs/pull/695
331// #[cfg(any(feature = "stm32g070", feature = "stm32g071", feature = "stm32g081"))]
332// dma!(
333//     channels: {
334//         C1: (ch1, htif1, tcif1, teif1, gif1, chtif1, ctcif1, cteif1, cgif1, C0),
335//         C2: (ch2, htif2, tcif2, teif2, gif2, chtif2, ctcif2, cteif2, cgif2, C1),
336//         C3: (ch3, htif3, tcif3, teif3, gif3, chtif3, ctcif3, cteif3, cgif3, C2),
337//         C4: (ch4, htif4, tcif4, teif4, gif4, chtif4, ctcif4, cteif4, cgif4, C3),
338//         C5: (ch5, htif5, tcif5, teif5, gif5, chtif5, ctcif5, cteif5, cgif5, C4),
339//         C6: (ch6, htif6, tcif6, teif6, gif6, chtif6, ctcif6, cteif6, cgif6, C5),
340//         C7: (ch7, htif7, tcif7, teif7, gif7, chtif7, ctcif7, cteif7, cgif7, C6),
341//     },
342// );
343
344#[cfg(any(feature = "stm32g030", feature = "stm32g031", feature = "stm32g041"))]
345dma!(
346    channels: {
347        C1: (ch1, htif1, tcif1, teif1, gif1, chtif1, ctcif1, cteif1, cgif1, C0),
348        C2: (ch2, htif2, tcif2, teif2, gif2, chtif2, ctcif2, cteif2, cgif2, C1),
349        C3: (ch3, htif3, tcif3, teif3, gif3, chtif3, ctcif3, cteif3, cgif3, C2),
350        C4: (ch4, htif4, tcif4, teif4, gif4, chtif4, ctcif4, cteif4, cgif4, C3),
351        C5: (ch5, htif5, tcif5, teif5, gif5, chtif5, ctcif5, cteif5, cgif5, C4),
352    },
353);
354
355#[cfg(any(feature = "stm32g030", feature = "stm32g031", feature = "stm32g041"))]
356impl DmaExt for DMA {
357    type Channels = Channels;
358
359    fn reset(self, rcc: &mut Rcc) -> Self {
360        // reset DMA
361        <DMA as Reset>::reset(rcc);
362        self
363    }
364
365    fn split(self, rcc: &mut Rcc, dmamux: DMAMUX) -> Self::Channels {
366        let muxchannels = dmamux.split();
367        // enable DMA clock
368        DMA::enable(rcc);
369
370        let mut channels = Channels {
371            ch1: C1 {
372                mux: muxchannels.ch0,
373            },
374            ch2: C2 {
375                mux: muxchannels.ch1,
376            },
377            ch3: C3 {
378                mux: muxchannels.ch2,
379            },
380            ch4: C4 {
381                mux: muxchannels.ch3,
382            },
383            ch5: C5 {
384                mux: muxchannels.ch4,
385            },
386            #[cfg(any(feature = "stm32g070", feature = "stm32g071", feature = "stm32g081"))]
387            ch6: C6 {
388                mux: muxchannels.ch5,
389            },
390            #[cfg(any(feature = "stm32g070", feature = "stm32g071", feature = "stm32g081"))]
391            ch7: C7 {
392                mux: muxchannels.ch6,
393            },
394        };
395        channels.reset();
396        channels
397    }
398}
399
400/// Trait implemented by DMA targets.
401pub trait Target {
402    /// Returns the correct DMAMUX index to configure DMA channel for this peripheral
403    fn dmamux(&self) -> crate::dmamux::DmaMuxIndex;
404
405    /// Enable DMA on the target
406    fn enable_dma(&mut self) {}
407    /// Disable DMA on the target
408    fn disable_dma(&mut self) {}
409}