stm32g473_hal_oppe/dma/
stream.rs

1//! DMA
2
3use super::{
4    config,
5    traits::sealed::{Bits, Sealed},
6    traits::*,
7    DmaDirection,
8};
9use core::marker::PhantomData;
10
11use crate::rcc::Rcc;
12use crate::stm32;
13
14use stm32::{DMA1, DMA2, DMAMUX};
15
16use crate::dma::config::DmaConfig;
17use core::ops::Deref;
18
19impl Sealed for DMA1 {}
20impl Sealed for DMA2 {}
21
22/// Type aliases for register blocks
23pub type DMARegisterBlock = stm32::dma1::RegisterBlock;
24pub type DMAMUXRegisterBlock = stm32::dmamux::RegisterBlock;
25
26/// Trait that represents an instance of a DMA peripheral
27pub trait Instance: Deref<Target = DMARegisterBlock> + Sealed {
28    /// Gives a pointer to the RegisterBlock.
29    fn ptr() -> *const DMARegisterBlock;
30
31    /// Gives a pointer to the DMAMUX used for this DMA.
32    fn mux_ptr() -> *const DMAMUXRegisterBlock;
33}
34
35impl Instance for DMA1 {
36    #[inline(always)]
37    fn ptr() -> *const DMARegisterBlock {
38        DMA1::ptr()
39    }
40
41    #[inline(always)]
42    fn mux_ptr() -> *const DMAMUXRegisterBlock {
43        DMAMUX::ptr()
44    }
45}
46
47impl Instance for DMA2 {
48    #[inline(always)]
49    fn ptr() -> *const DMARegisterBlock {
50        DMA2::ptr()
51    }
52
53    #[inline(always)]
54    fn mux_ptr() -> *const DMAMUXRegisterBlock {
55        DMAMUX::ptr()
56    }
57}
58
59/// DMA interrupts
60#[derive(Debug, Clone, Copy)]
61pub struct DmaInterrupts {
62    transfer_complete: bool,
63    transfer_error: bool,
64    half_transfer: bool,
65}
66
67/// Stream 0 on DMA
68pub struct Stream0<DMA> {
69    _dma: PhantomData<DMA>,
70}
71/// Stream 1 on DMA
72pub struct Stream1<DMA> {
73    _dma: PhantomData<DMA>,
74}
75/// Stream 2 on DMA
76pub struct Stream2<DMA> {
77    _dma: PhantomData<DMA>,
78}
79/// Stream 3 on DMA
80pub struct Stream3<DMA> {
81    _dma: PhantomData<DMA>,
82}
83/// Stream 4 on DMA
84pub struct Stream4<DMA> {
85    _dma: PhantomData<DMA>,
86}
87/// Stream 5 on DMA
88pub struct Stream5<DMA> {
89    _dma: PhantomData<DMA>,
90}
91/// Stream 6 on DMA
92pub struct Stream6<DMA> {
93    _dma: PhantomData<DMA>,
94}
95/// Stream 7 on DMA
96pub struct Stream7<DMA> {
97    _dma: PhantomData<DMA>,
98}
99
100impl<DMA> Sealed for Stream0<DMA> {}
101impl<DMA> Sealed for Stream1<DMA> {}
102impl<DMA> Sealed for Stream2<DMA> {}
103impl<DMA> Sealed for Stream3<DMA> {}
104impl<DMA> Sealed for Stream4<DMA> {}
105impl<DMA> Sealed for Stream5<DMA> {}
106impl<DMA> Sealed for Stream6<DMA> {}
107impl<DMA> Sealed for Stream7<DMA> {}
108
109/// Alias for a tuple with all DMA streams.
110pub struct StreamsTuple<T>(
111    pub Stream0<T>,
112    pub Stream1<T>,
113    pub Stream2<T>,
114    pub Stream3<T>,
115    pub Stream4<T>,
116    pub Stream5<T>,
117    #[cfg(not(any(feature = "stm32g431", feature = "stm32g441",)))] pub Stream6<T>,
118    #[cfg(not(any(feature = "stm32g431", feature = "stm32g441",)))] pub Stream7<T>,
119);
120
121pub trait DMAExt<I> {
122    fn split(self, rcc: &Rcc) -> StreamsTuple<I>;
123}
124
125impl DMAExt<Self> for DMA1 {
126    fn split(self, rcc: &Rcc) -> StreamsTuple<DMA1> {
127        // Enable DMAMux is not yet enabled
128        if !rcc.rb.ahb1enr.read().dmamuxen().bit_is_set() {
129            // Enable peripheral
130            rcc.rb.ahb1enr.modify(|_, w| w.dmamuxen().set_bit());
131        }
132
133        // Enable peripheral
134        rcc.rb.ahb1enr.modify(|_, w| w.dma1en().set_bit());
135
136        StreamsTuple::new(self)
137    }
138}
139
140impl DMAExt<Self> for DMA2 {
141    fn split(self, rcc: &Rcc) -> StreamsTuple<DMA2> {
142        // Enable DMAMux is not yet enabled
143        if !rcc.rb.ahb1enr.read().dmamuxen().bit_is_set() {
144            // Enable peripheral
145            rcc.rb.ahb1enr.modify(|_, w| w.dmamuxen().set_bit());
146        }
147
148        // Enable peripheral
149        rcc.rb.ahb1enr.modify(|_, w| w.dma2en().set_bit());
150
151        StreamsTuple::new(self)
152    }
153}
154
155impl<I: Instance> StreamsTuple<I> {
156    /// Splits the DMA peripheral into streams.
157    pub(crate) fn new(_regs: I) -> Self {
158        Self(
159            Stream0 { _dma: PhantomData },
160            Stream1 { _dma: PhantomData },
161            Stream2 { _dma: PhantomData },
162            Stream3 { _dma: PhantomData },
163            Stream4 { _dma: PhantomData },
164            Stream5 { _dma: PhantomData },
165            #[cfg(not(any(feature = "stm32g431", feature = "stm32g441",)))]
166            Stream6 { _dma: PhantomData },
167            #[cfg(not(any(feature = "stm32g431", feature = "stm32g441",)))]
168            Stream7 { _dma: PhantomData },
169        )
170    }
171}
172
173// Macro that creates a struct representing a stream on either DMA controller
174//
175// The implementation does the heavy lifting of mapping to the right fields on
176// the stream
177macro_rules! dma_stream {
178    ($(($name:ident, $number:expr,
179        regs => $ccr:ident, $cparX:ident, $cmarX:ident, $cndtrX:ident,
180        fields => $tcif:ident, $htif:ident, $teif:ident, $gif:ident, $tcisr:ident, $htisr:ident, $teisr:ident, $gisr:ident,
181        dmamux => $cXcr:ident,)
182    ),+$(,)*) => {
183        $(
184            impl<I: Instance> Stream for $name<I> {
185
186                const NUMBER: usize = $number;
187                type Config = DmaConfig;
188                type Interrupts = DmaInterrupts;
189
190                fn apply_config(&mut self, config: DmaConfig) {
191                    self.set_priority(config.priority);
192                    self.set_memory_increment(config.memory_increment);
193                    self.set_peripheral_increment(config.peripheral_increment);
194                    self.set_circular_buffer(config.circular_buffer);
195                    self.set_transfer_complete_interrupt_enable(
196                        config.transfer_complete_interrupt
197                    );
198                    self.set_half_transfer_interrupt_enable(config.half_transfer_interrupt);
199                    self.set_transfer_error_interrupt_enable(
200                        config.transfer_error_interrupt
201                    );
202               }
203
204                #[inline(always)]
205                fn clear_interrupts(&mut self) {
206                    //NOTE(unsafe) Atomic write with no side-effects and we only access the bits
207                    // that belongs to the StreamX
208                    let dma = unsafe { &*I::ptr() };
209                    dma.ifcr.write(|w| w
210                                    .$tcif().set_bit() //Clear transfer complete interrupt flag
211                                    .$htif().set_bit() //Clear half transfer interrupt flag
212                                    .$teif().set_bit() //Clear transfer error interrupt flag
213                                    .$gif().set_bit() //Clear global interrupt flag
214                    );
215                    let _ = dma.isr.read();
216                    let _ = dma.isr.read(); // Delay 2 peripheral clocks
217                }
218
219                #[inline(always)]
220                fn clear_transfer_complete_flag(&mut self) {
221                    //NOTE(unsafe) Atomic write with no side-effects and we only access the bits
222                    // that belongs to the StreamX
223                    let dma = unsafe { &*I::ptr() };
224                    dma.ifcr.write(|w| w.$tcif().set_bit());
225                }
226
227                #[inline(always)]
228                fn clear_transfer_complete_interrupt(&mut self) {
229                    self.clear_transfer_complete_flag();
230                    //NOTE(unsafe) Atomic read with no side-effects.
231                    let dma = unsafe { &*I::ptr() };
232                    let _ = dma.isr.read();
233                    let _ = dma.isr.read(); // Delay 2 peripheral clocks
234                }
235
236                #[inline(always)]
237                fn clear_transfer_error_interrupt(&mut self) {
238                    //NOTE(unsafe) Atomic write with no side-effects and we only access the bits
239                    // that belongs to the StreamX
240                    let dma = unsafe { &*I::ptr() };
241                    dma.ifcr.write(|w| w.$teif().set_bit());
242                    let _ = dma.isr.read();
243                    let _ = dma.isr.read(); // Delay 2 peripheral clocks
244                }
245
246                #[inline(always)]
247                fn get_transfer_complete_flag() -> bool {
248                    //NOTE(unsafe) Atomic read with no side effects
249                    let dma = unsafe { &*I::ptr() };
250                    dma.isr.read().$tcisr().bit_is_set()
251                }
252
253                #[inline(always)]
254                unsafe fn enable(&mut self) {
255                    //NOTE(unsafe) We only access the registers that belongs to the StreamX
256                    let dma = &*I::ptr();
257                    dma.$ccr.modify(|_, w| w.en().set_bit());
258                }
259
260                #[inline(always)]
261                fn is_enabled() -> bool {
262                    //NOTE(unsafe) Atomic read with no side effects
263                    let dma = unsafe { &*I::ptr() };
264                    dma.$ccr.read().en().bit_is_set()
265                }
266
267                fn disable(&mut self) {
268                    if Self::is_enabled() {
269                        //NOTE(unsafe) We only access the registers that belongs to the StreamX
270                        let dma = unsafe { &*I::ptr() };
271
272                        // Aborting an on-going transfer might cause interrupts to fire, disable
273                        // them
274                        let interrupts = Self::get_interrupts_enable();
275                        self.disable_interrupts();
276
277                        dma.$ccr.modify(|_, w| w.en().clear_bit());
278                        while Self::is_enabled() {}
279
280                        self.clear_interrupts();
281                        self.enable_interrupts(interrupts);
282                    }
283                }
284
285                #[inline(always)]
286                fn set_request_line(&mut self, request_line: u8) {
287                    //NOTE(unsafe) We only access the registers that belongs to the StreamX
288                    let dmamux = unsafe { &*I::mux_ptr() };
289                    unsafe {
290                        dmamux.$cXcr
291                            .modify(|_, w| w.dmareq_id().bits(request_line));
292                    }
293                }
294
295                #[inline(always)]
296                fn set_priority(&mut self, priority: config::Priority) {
297                    //NOTE(unsafe) We only access the registers that belongs to the StreamX
298                    let dma = unsafe { &*I::ptr() };
299                    dma.$ccr.modify(|_, w| unsafe { w.pl().bits(priority.bits()) });
300                }
301
302                #[inline(always)]
303                fn disable_interrupts(&mut self) {
304                    //NOTE(unsafe) We only access the registers that belongs to the StreamX
305                    let dmacr = &unsafe { &*I::ptr() }.$ccr;
306                    dmacr.modify(|_, w| w
307                        .tcie().clear_bit()
308                        .teie().clear_bit()
309                        .htie().clear_bit());
310                    let _ = dmacr.read();
311                    let _ = dmacr.read(); // Delay 2 peripheral clocks
312                }
313
314                #[inline(always)]
315                fn enable_interrupts(&mut self, interrupt: Self::Interrupts) {
316                    //NOTE(unsafe) We only access the registers that belongs to the StreamX
317                    let dma = unsafe { &*I::ptr() };
318                    dma.$ccr.modify(|_, w| w
319                                                   .tcie().bit(interrupt.transfer_complete)
320                                                   .teie().bit(interrupt.transfer_error)
321                                                   .htie().bit(interrupt.half_transfer)
322                    );
323                }
324
325                #[inline(always)]
326                fn get_interrupts_enable() -> Self::Interrupts {
327                    //NOTE(unsafe) We only access the registers that belongs to the StreamX
328                    let dma = unsafe { &*I::ptr() };
329                    let cr = dma.$ccr.read();
330
331                    DmaInterrupts {
332                        transfer_complete: cr.tcie().bit_is_set(),
333                        half_transfer: cr.htie().bit_is_set(),
334                        transfer_error: cr.teie().bit_is_set()
335                    }
336                }
337
338
339                #[inline(always)]
340                fn set_transfer_complete_interrupt_enable(&mut self, transfer_complete_interrupt: bool) {
341                    //NOTE(unsafe) We only access the registers that belongs to the StreamX
342                    let dmacr = &unsafe { &*I::ptr() }.$ccr;
343                    dmacr.modify(|_, w| w.tcie().bit(transfer_complete_interrupt));
344                    let _ = dmacr.read();
345                    let _ = dmacr.read(); // Delay 2 peripheral clocks
346                }
347
348                #[inline(always)]
349                fn set_transfer_error_interrupt_enable(&mut self, transfer_error_interrupt: bool) {
350                    //NOTE(unsafe) We only access the registers that belongs to the StreamX
351                    let dmacr = &unsafe { &*I::ptr() }.$ccr;
352                    dmacr.modify(|_, w| w.teie().bit(transfer_error_interrupt));
353                    let _ = dmacr.read();
354                    let _ = dmacr.read(); // Delay 2 peripheral clocks
355                }
356
357                #[inline(always)]
358                fn set_half_transfer_interrupt_enable(&mut self, half_transfer_interrupt: bool) {
359                    //NOTE(unsafe) We only access the registers that belongs to the StreamX
360                    let dmacr = &unsafe { &*I::ptr() }.$ccr;
361                    dmacr.modify(|_, w| w.htie().bit(half_transfer_interrupt));
362                    let _ = dmacr.read();
363                    let _ = dmacr.read(); // Delay 2 peripheral clocks
364                }
365
366                #[inline(always)]
367                fn get_half_transfer_flag() -> bool {
368                    //NOTE(unsafe) Atomic read with no side effects
369                    let dma = unsafe { &*I::ptr() };
370                    dma.isr.read().$htisr().bit_is_set()
371                }
372
373                #[inline(always)]
374                fn clear_half_transfer_interrupt(&mut self) {
375                    //NOTE(unsafe) Atomic write with no side-effects and we only access the bits
376                    // that belongs to the StreamX
377                    let dma = unsafe { &*I::ptr() };
378                    dma.ifcr.write(|w| w.$htif().set_bit());
379                    let _ = dma.isr.read();
380                    let _ = dma.isr.read(); // Delay 2 peripheral clocks
381                }
382
383                #[inline(always)]
384                unsafe fn set_peripheral_address(&mut self, value: u32) {
385                    //NOTE(unsafe) We only access the registers that belongs to the StreamX
386                    let dma = &*I::ptr();
387                    dma.$cparX.write(|w| w.pa().bits(value));
388                }
389
390                #[inline(always)]
391                unsafe fn set_memory_address(&mut self, value: u32) {
392                    //NOTE(unsafe) We only access the registers that belongs to the StreamX
393                    let dma = &*I::ptr();
394                    dma.$cmarX.write(|w| w.ma().bits(value) );
395                }
396
397                #[inline(always)]
398                fn get_memory_address(&self) -> u32 {
399                    //NOTE(unsafe) We only access the registers that belongs to the StreamX
400                    let dma = unsafe { &*I::ptr() };
401                    dma.$cmarX.read().ma().bits()
402                }
403
404                #[inline(always)]
405                fn set_number_of_transfers(&mut self, value: u16) {
406                    //NOTE(unsafe) We only access the registers that belongs to the StreamX
407                    let dma = unsafe { &*I::ptr() };
408                    dma.$cndtrX.write(|w| unsafe {w.ndt().bits(value) });
409                }
410
411                #[inline(always)]
412                fn get_number_of_transfers() -> u16 {
413                    //NOTE(unsafe) We only access the registers that belongs to the StreamX
414                    let dma = unsafe { &*I::ptr() };
415                    dma.$cndtrX.read().ndt().bits()
416                }
417                #[inline(always)]
418                unsafe fn set_memory_size(&mut self, size: u8) {
419                    //NOTE(unsafe) We only access the registers that belongs to the StreamX
420                    let dma = &*I::ptr();
421                    dma.$ccr.modify(|_, w| w.msize().bits(size));
422                }
423
424                #[inline(always)]
425                unsafe fn set_peripheral_size(&mut self, size: u8) {
426                    //NOTE(unsafe) We only access the registers that belongs to the StreamX
427                    let dma = &*I::ptr();
428                    dma.$ccr.modify(|_, w| w.psize().bits(size));
429                }
430
431                #[inline(always)]
432                fn set_memory_increment(&mut self, increment: bool) {
433                    //NOTE(unsafe) We only access the registers that belongs to the StreamX
434                    let dma = unsafe { &*I::ptr() };
435                    dma.$ccr.modify(|_, w| w.minc().bit(increment));
436                }
437
438                #[inline(always)]
439                fn set_peripheral_increment(&mut self, increment: bool) {
440                    //NOTE(unsafe) We only access the registers that belongs to the StreamX
441                    let dma = unsafe { &*I::ptr() };
442                    dma.$ccr.modify(|_, w| w.pinc().bit(increment));
443                }
444
445                #[inline(always)]
446                fn set_direction(&mut self, direction: DmaDirection) {
447                    //NOTE(unsafe) We only access the registers that belongs to the StreamX
448                    let dma = unsafe { &*I::ptr() };
449                    dma.$ccr.modify(|_, w| {
450                        match direction {
451                            DmaDirection::PeripheralToMemory =>
452                                w.dir().clear_bit().mem2mem().clear_bit(),
453                            DmaDirection::MemoryToPeripheral =>
454                                w.dir().set_bit().mem2mem().clear_bit(),
455                            DmaDirection::MemoryToMemory =>
456                                w.mem2mem().set_bit().dir().clear_bit(),
457                        }
458                    });
459                }
460
461                #[inline(always)]
462                fn set_circular_buffer(&mut self, circular_buffer: bool) {
463                    //NOTE(unsafe) We only access the registers that belongs to the StreamX
464                    let dma = unsafe { &*I::ptr() };
465                    dma.$ccr.modify(|_, w| w.circ().bit(circular_buffer));
466                }
467            }
468
469            impl<I: Instance> $name<I> {
470                #[inline(always)]
471                pub fn clear_half_transfer_interrupt(&mut self) {
472                    //NOTE(unsafe) Atomic write with no side-effects and we only access the bits
473                    // that belongs to the StreamX
474                    let dma = unsafe { &*I::ptr() };
475                    dma.ifcr.write(|w| w.$htif().set_bit());
476                    let _ = dma.isr.read();
477                    let _ = dma.isr.read(); // Delay 2 peripheral clocks
478                }
479
480                #[inline(always)]
481                pub fn get_half_transfer_flag() -> bool {
482                    //NOTE(unsafe) Atomic read with no side effects
483                    let dma = unsafe { &*I::ptr() };
484                    dma.isr.read().$htisr().bit_is_set()
485                }
486
487                #[inline(always)]
488                pub fn set_half_transfer_interrupt_enable(&mut self, half_transfer_interrupt: bool) {
489                    //NOTE(unsafe) We only access the registers that belongs to the StreamX
490                    let dmacr = &unsafe { &*I::ptr() }.$ccr;
491                    dmacr.modify(|_, w| w.htie().bit(half_transfer_interrupt));
492                    let _ = dmacr.read();
493                    let _ = dmacr.read(); // Delay 2 peripheral clocks
494                }
495            }
496        )+
497    };
498}
499
500dma_stream!(
501    // Note: the field names start from one, unlike the RM where they start from
502    // zero. May need updating if it gets fixed upstream.
503    (
504        Stream0, 0,
505        regs => ccr1, cpar1, cmar1, cndtr1,
506        fields => tcif1, htif1, teif1, gif1, tcif1, htif1, teif1, gif1,
507        dmamux => c0cr,
508    ),
509    (
510        Stream1, 1,
511        regs => ccr2, cpar2, cmar2, cndtr2,
512        fields => tcif2, htif2, teif2, gif2, tcif2, htif2, teif2, gif2,
513        dmamux => c1cr,
514    ),
515    (
516        Stream2, 2,
517        regs => ccr3, cpar3, cmar3, cndtr3,
518        fields => tcif3, htif3, teif3, gif3, tcif3, htif3, teif3, gif3,
519        dmamux => c2cr,
520    ),
521    (
522        Stream3, 3,
523        regs => ccr4, cpar4, cmar4, cndtr4,
524        fields => tcif4, htif4, teif4, gif4, tcif4, htif4, teif4, gif4,
525        dmamux => c3cr,
526    ),
527    (
528        Stream4, 4,
529        regs => ccr5, cpar5, cmar5, cndtr5,
530        fields => tcif5, htif5, teif5, gif5, tcif5, htif5, teif5, gif5,
531        dmamux => c4cr,
532    ),
533    (
534        Stream5, 5,
535        regs => ccr6, cpar6, cmar6, cndtr6,
536        fields => tcif6, htif6, teif6, gif6, tcif6, htif6, teif6, gif6,
537        dmamux => c5cr,
538    ),
539    (
540        Stream6, 6,
541        regs => ccr7, cpar7, cmar7, cndtr7,
542        fields => tcif7, htif7, teif7, gif7, tcif7, htif7, teif7, gif7,
543        dmamux => c6cr,
544    ),
545    (
546        Stream7, 7,
547        regs => ccr8, cpar8, cmar8, cndtr8,
548        fields => tcif8, htif8, teif8, gif8, tcif8, htif8, teif8, gif8,
549        dmamux => c7cr,
550    ),
551);