stm32_hal2/
dma.rs

1//! Support for the Direct Memory Access (DMA) peripheral. This module handles initialization, and transfer
2//! configuration for DMA. The `Dma::cfg_channel` method is called by modules that use DMA.
3
4// todo: This module could be greatly simplified if [this issue](https://github.com/stm32-rs/stm32-rs/issues/610)
5// todo is addressed: Ie H7 PAC approach adopted by other modules.
6
7// todo: Use this clip or something similar to end terminate while loops, as in other modules.
8// let mut i = 0;
9// while asdf {
10//     i += 1;
11//     if i >= MAX_ITERS {
12//         return Err(Error::Hardware);
13//     }
14// }
15
16use core::{
17    ops::Deref,
18    sync::atomic::{self, Ordering},
19};
20
21use crate::{
22    MAX_ITERS,
23    pac::{self, RCC},
24    util::rcc_en_reset,
25};
26
27cfg_if! {
28    if #[cfg(all(feature = "g0", not(any(feature = "g0b1", feature = "g0c1"))))] {
29        use crate::pac::{dma as dma1, DMA as DMA1};
30    } else if #[cfg(feature = "f3x4")] {
31        use crate::pac::{dma1, DMA1};
32    }
33    else {
34        use crate::pac::{dma1, dma2, DMA1, DMA2};
35    }
36}
37
38// use embedded_dma::{ReadBuffer, WriteBuffer};
39use cfg_if::cfg_if;
40#[cfg(any(feature = "g0", feature = "g4", feature = "wl"))]
41use pac::DMAMUX;
42// todo: DMAMUX2 support (Not sure if WB has it, but H7 has both).
43#[cfg(any(feature = "l5", feature = "wb", feature = "h7"))]
44use pac::DMAMUX1 as DMAMUX;
45#[cfg(feature = "h7")]
46use pac::DMAMUX2;
47use paste::paste;
48
49// todo: Several sections of this are only correct for DMA1.
50
51#[derive(Clone, Copy)]
52pub enum DmaPeriph {
53    Dma1,
54    #[cfg(not(any(
55        feature = "f3x4",
56        all(feature = "g0", not(any(feature = "g0b1", feature = "g0c1"))),
57        feature = "wb",
58    )))] // todo: f3x4 too
59    Dma2,
60}
61
62#[derive(Copy, Clone)]
63#[repr(usize)]
64#[cfg(not(any(feature = "h7", feature = "wl", feature = "wb")))]
65/// A list of DMA input sources. The integer values represent their DMAMUX register value, on
66/// MCUs that use this. G4 RM, Table 91: DMAMUX: Assignment of multiplexer inputs to resources.
67pub enum DmaInput {
68    // This (on G4) goes up to 115. For now, just implement things we're likely
69    // to use in this HAL. Make sure this is compatible beyond G4.
70    Adc1 = 5,
71    Dac1Ch1 = 6,
72    Dac1Ch2 = 7,
73    Tim6Up = 8,
74    Tim7Up = 9,
75    Spi1Rx = 10,
76    Spi1Tx = 11,
77    Spi2Rx = 12,
78    Spi2Tx = 13,
79    Spi3Rx = 14,
80    Spi3Tx = 15,
81    I2c1Rx = 16,
82    I2c1Tx = 17,
83    I2c2Rx = 18,
84    I2c2Tx = 19,
85    I2c3Rx = 20,
86    I2c3Tx = 21,
87    I2c4Rx = 22,
88    I2c4Tx = 23,
89    Usart1Rx = 24,
90    Usart1Tx = 25,
91    Usart2Rx = 26,
92    Usart2Tx = 27,
93    Usart3Rx = 28,
94    Usart3Tx = 29,
95    Uart4Rx = 30,
96    Uart4Tx = 31,
97    Uart5Rx = 32,
98    Uart5Tx = 33,
99    Lpuart1Rx = 34,
100    Lpuart1Tx = 35,
101    Adc2 = 36,
102    Adc3 = 37,
103    Adc4 = 38,
104    Adc5 = 39,
105    Quadspi = 40,
106    Dac2Ch1 = 41,
107    Tim1Ch1 = 42,
108    Tim1Ch2 = 43,
109    Tim1Ch3 = 44,
110    Tim1Ch4 = 45,
111    TimUp = 46,
112    Tim1Trig = 47,
113    Tim1Com = 48,
114    Tim8Ch1 = 49,
115    Tim8Ch2 = 50,
116    Tim8Ch3 = 51,
117    Tim8Ch4 = 52,
118    Tim8Up = 53,
119    Tim8Trig = 54,
120    Tim8Com = 55,
121    Tim2Ch1 = 56,
122    Tim2Ch2 = 57,
123    Tim2Ch3 = 58,
124    Tim2Ch4 = 59,
125    Tim2Up = 60,
126    Tim3Ch1 = 61,
127    Tim3Ch2 = 62,
128    Tim3Ch3 = 63,
129    Tim3Ch4 = 64,
130    Tim3Up = 65,
131    Tim3Trig = 66,
132    Tim4Ch1 = 67,
133    Tim4Ch2 = 68,
134    Tim4Ch3 = 69,
135    Tim4Ch4 = 70,
136    Tim4Up = 71,
137    Sai1A = 108,
138    Sai1B = 109,
139    // todo: These SAI2 values are bogus; can't find on G4 DMA mux.
140    Sai2A = 203,
141    Sai2B = 204,
142    // todo: Can't find DFSDM periph on G4 rm: These assigned values are bogus.
143    Dfsdm1F0 = 200,
144    Dfsdm1F1 = 201,
145    Dfsdm1F2 = 205,
146    Dfsdm1F3 = 206,
147}
148
149#[derive(Copy, Clone)]
150#[repr(usize)]
151#[cfg(feature = "wl")]
152/// WL RM, 14.3.2: DMAMUX1 mapping
153pub enum DmaInput {
154    Adc = 5,
155    DacOut1 = 6,
156    // Dac1Ch2 = 7,
157    Spi1Rx = 7,
158    Spi1Tx = 8,
159    Spi2Rx = 9,
160    Spi2Tx = 10,
161    I2c1Rx = 11,
162    I2c1Tx = 12,
163    I2c2Rx = 13,
164    I2c2Tx = 14,
165    I2c3Rx = 15,
166    I2c3Tx = 16,
167    Usart1Rx = 17,
168    Usart1Tx = 18,
169    Usart2Rx = 19,
170    Usart2Tx = 20,
171    Lpuart1Rx = 21,
172    Lpuart1Tx = 22,
173    Tim1Ch1 = 23,
174    Tim1Ch2 = 24,
175    Tim1Ch3 = 25,
176    Tim1Ch4 = 26,
177    TimUp = 27,
178    Tim1Trig = 28,
179    Tim1Com = 29,
180    Tim2Ch1 = 30,
181    Tim2Ch2 = 31,
182    Tim2Ch3 = 32,
183    Tim2Ch4 = 33,
184    Tim2Up = 34,
185    Tim16Ch1 = 35,
186    Tim16Up = 36,
187    Tim17Ch1 = 37,
188    Tim17Up = 38,
189    AesIn = 39,
190    AesOut = 40,
191    SubghzSpiRx = 41,
192    SubghzSpiTx = 42,
193}
194
195#[derive(Copy, Clone)]
196#[repr(usize)]
197#[cfg(feature = "wb")]
198/// WB RM, 12.3.2: DMAMUX mapping
199pub enum DmaInput {
200    Adc1 = 5,
201    Spi1Rx = 6,
202    Spi1Tx = 7,
203    Spi2Rx = 8,
204    Spi2Tx = 9,
205    I2c1Rx = 10,
206    I2c1Tx = 11,
207    I2c3Rx = 12,
208    I2c3Tx = 13,
209    Usart1Rx = 14,
210    Usart1Tx = 15,
211    Lpuart1Rx = 16,
212    Lpuart1Tx = 17,
213    Sai1A = 18,
214    Sai1B = 19,
215    Quadspi = 20,
216    Tim1Ch1 = 21,
217    Tim1Ch2 = 22,
218    Tim1Ch3 = 23,
219    Tim1Ch4 = 24,
220    TimUp = 25,
221    Tim1Trig = 26,
222    Tim1Com = 27,
223    Tim2Ch1 = 28,
224    Tim2Ch2 = 29,
225    Tim2Ch3 = 30,
226    Tim2Ch4 = 31,
227    Tim2Up = 32,
228    Tim16Ch1 = 33,
229    Tim16Up = 34,
230    Tim17Ch1 = 35,
231    Tim17Up = 36,
232    Aes1In = 37,
233    Aes1Out = 38,
234    Aes2In = 39,
235    Aes2Out = 40,
236}
237
238// todo: Trigger, synchronization etc mappings. Perhaps DmaTrigger, DmaSync enums etc.
239
240#[derive(Copy, Clone)]
241#[repr(usize)]
242#[cfg(feature = "h7")]
243/// A list of DMA input sources. The integer values represent their DMAMUX register value, on
244/// MCUs that use this. H743 RM, Table 121: DMAMUX1: Assignment of multiplexer inputs to resources.
245/// (Table 118 in RM0468)
246/// Note that this is only for DMAMUX1
247pub enum DmaInput {
248    Adc1 = 9,
249    Adc2 = 10,
250    Tim1Ch1 = 11,
251    Tim1Ch2 = 12,
252    Tim1Ch3 = 13,
253    Tim1Ch4 = 14,
254    Tim1Up = 15,
255    Tim1Trig = 16,
256    Tim1Com = 17,
257    Tim2Ch1 = 18,
258    Tim2Ch2 = 19,
259    Tim2Ch3 = 20,
260    Tim2Ch4 = 21,
261    Tim2Up = 22,
262    Tim3Ch1 = 23,
263    Tim3Ch2 = 24,
264    Tim3Ch3 = 25,
265    Tim3Ch4 = 26,
266    Tim3Up = 27,
267    Tim3Trig = 28,
268    Tim4Ch1 = 29,
269    Tim4Ch2 = 30,
270    Tim4Ch3 = 31,
271    Tim4Up = 32,
272    I2c1Rx = 33,
273    I2c1Tx = 34,
274    I2c2Rx = 35,
275    I2c2Tx = 36,
276    Spi1Rx = 37,
277    Spi1Tx = 38,
278    Spi2Rx = 39,
279    Spi2Tx = 40,
280    Usart1Rx = 41,
281    Usart1Tx = 42,
282    Usart2Rx = 43,
283    Usart2Tx = 44,
284    Usart3Rx = 45,
285    Usart3Tx = 46,
286    Tim8Ch1 = 47,
287    Tim8Ch2 = 48,
288    Tim8Ch3 = 49,
289    Tim8Ch4 = 50,
290    Tim8Up = 51,
291    Tim8Trig = 52,
292    Tim8Com = 53,
293    Tim5Ch1 = 55,
294    Tim5Ch2 = 56,
295    Tim5Ch3 = 57,
296    Tim5Ch4 = 58,
297    Tim5Up = 59,
298    Tim5Trig = 60,
299    Spi3Rx = 61,
300    Spi3Tx = 62,
301    Uart4Rx = 63,
302    Uart4Tx = 64,
303    Uart5Rx = 65,
304    Uart5Tx = 66,
305    DacCh1 = 67,
306    DacCh2 = 68,
307    Tim6Up = 69,
308    Tim7Up = 70,
309    Uart6Rx = 71,
310    Uart6Tx = 72,
311    I2c3Rx = 73,
312    I2c3Tx = 74,
313    Dcmi = 75,
314    CrypIn = 76,
315    CrypOut = 77,
316    HashIn = 78,
317    Uart7Rx = 79,
318    Uart7Tx = 80,
319    Uart8Rx = 81,
320    Uart8Tx = 82,
321    Sai1A = 87,
322    Sai1B = 88,
323    Sai2A = 89,
324    Sai2B = 90,
325    Dfsdm1F0 = 101,
326    Dfsdm1F1 = 102,
327    Dfsdm1F2 = 103,
328    Dfsdm1F3 = 104,
329    Sai3A = 113,
330    Sai3B = 114,
331    Adc3 = 115,
332    Uart9Rx = 116,
333    Uart9Tx = 117,
334    Uart10Rx = 118,
335    Uart10Tx = 119,
336}
337
338#[derive(Copy, Clone)]
339#[repr(usize)]
340#[cfg(feature = "h7")]
341/// A list of DMA input sources for DMAMUX2. Used for BDMA. See H742 RM, Table 124.
342pub enum DmaInput2 {
343    Lpuart1Rx = 9,
344    Lpuart1Tx = 10,
345    Spi6Rx = 11,
346    Spi6Tx = 12,
347    I2c4Rx = 13,
348    I3crTx = 14,
349    Sai4A = 15,
350    Sai4B = 16,
351}
352
353impl DmaInput {
354    #[cfg(any(feature = "f3", feature = "l4"))]
355    /// Select the hard set channel associated with a given input source. See L44 RM, Table 41.
356    pub fn dma1_channel(&self) -> DmaChannel {
357        match self {
358            Self::Adc1 => DmaChannel::C1,
359            Self::Dac1Ch1 => DmaChannel::C3,
360            Self::Dac1Ch2 => DmaChannel::C4,
361            // Self::Tim6Up => 8,
362            // Self::Tim7Up => 9,
363            Self::Spi1Rx => DmaChannel::C2,
364            Self::Spi1Tx => DmaChannel::C3,
365            Self::Spi2Rx => DmaChannel::C4,
366            Self::Spi2Tx => DmaChannel::C5,
367            // Self::Spi3Rx => 14,
368            // Self::Spi3Tx => 15,
369            Self::I2c1Rx => DmaChannel::C7,
370            Self::I2c1Tx => DmaChannel::C6,
371            Self::I2c2Rx => DmaChannel::C5,
372            Self::I2c2Tx => DmaChannel::C4,
373            Self::I2c3Rx => DmaChannel::C3,
374            // Self::I2c3Tx => 21,
375            // Self::I2c4Rx => 22,
376            // Self::I2c4Tx => 23,
377            Self::Usart1Rx => DmaChannel::C5,
378            Self::Usart1Tx => DmaChannel::C4,
379            Self::Usart2Rx => DmaChannel::C6,
380            Self::Usart2Tx => DmaChannel::C7,
381            Self::Usart3Rx => DmaChannel::C3,
382            Self::Usart3Tx => DmaChannel::C2,
383            // Self::Uart4Rx => 30,
384            // Self::Uart4Tx => 31,
385            // Self::Uart5Rx => 32,
386            // Self::Uart5Tx => 33,
387            // Self::Lpuart1Rx => 34,
388            // Self::Lpuart1Tx => 35,
389            Self::Adc2 => DmaChannel::C2,
390            // Self::Adc3 => 37,
391            // Self::Adc4 => 38,
392            // Self::Adc5 => 39,
393            // Note: Sai1 appears to be DMA2 only.
394            Self::Sai2A => DmaChannel::C6,
395            Self::Sai2B => DmaChannel::C7,
396            Self::Dfsdm1F0 => DmaChannel::C4,
397            Self::Dfsdm1F1 => DmaChannel::C5,
398            Self::Dfsdm1F2 => DmaChannel::C6,
399            Self::Dfsdm1F3 => DmaChannel::C7,
400            _ => unimplemented!(),
401        }
402    }
403
404    #[cfg(feature = "l4")]
405    /// Find the value to set in the DMA_CSELR register, for L4. Ie, channel select value for a given DMA input.
406    /// See L44 RM, Table 41.
407    pub fn dma1_channel_select(&self) -> u8 {
408        match self {
409            Self::Adc1 => 0b000,
410            Self::Dac1Ch1 => 0b0110,
411            Self::Dac1Ch2 => 0b0101,
412            // Self::Tim6Up => 8,
413            // Self::Tim7Up => 9,
414            Self::Spi1Rx => 0b001,
415            Self::Spi1Tx => 0b001,
416            Self::Spi2Rx => 0b001,
417            Self::Spi2Tx => 0b001,
418            // Self::Spi3Rx => 14,
419            // Self::Spi3Tx => 15,
420            Self::I2c1Rx => 0b011,
421            Self::I2c1Tx => 0b011,
422            Self::I2c2Rx => 0b011,
423            Self::I2c2Tx => 0b011,
424            Self::I2c3Rx => 0b011,
425            // Self::I2c3Tx => 21,
426            // Self::I2c4Rx => 22,
427            // Self::I2c4Tx => 23,
428            Self::Usart1Rx => 0b010,
429            Self::Usart1Tx => 0b010,
430            Self::Usart2Rx => 0b010,
431            Self::Usart2Tx => 0b010,
432            Self::Usart3Rx => 0b010,
433            Self::Usart3Tx => 0b010,
434            // Self::Uart4Rx => 30,
435            // Self::Uart4Tx => 31,
436            // Self::Uart5Rx => 32,
437            // Self::Uart5Tx => 33,
438            // Self::Lpuart1Rx => 34,
439            // Self::Lpuart1Tx => 35,
440            Self::Adc2 => 0b000,
441            // Self::Adc3 => 37,
442            // Self::Adc4 => 38,
443            // Self::Adc5 => 39,
444            Self::Dfsdm1F0 => 0b0000,
445            Self::Dfsdm1F1 => 0b0000,
446            Self::Dfsdm1F2 => 0b0000, // todo: QC?
447            Self::Dfsdm1F3 => 0b0000,
448            _ => unimplemented!(),
449        }
450    }
451}
452
453#[derive(Copy, Clone)]
454#[repr(u8)]
455/// L4 RM, 11.4.3, "DMA arbitration":
456/// The priorities are managed in two stages:
457/// • software: priority of each channel is configured in the DMA_CCRx register, to one of
458/// the four different levels:
459/// – very high
460/// – high
461/// – medium
462/// – low
463/// • hardware: if two requests have the same software priority level, the channel with the
464/// lowest index gets priority. For example, channel 2 gets priority over channel 4.
465/// Only write to this when the channel is disabled.
466pub enum Priority {
467    Low = 0b00,
468    Medium = 0b01,
469    High = 0b10,
470    VeryHigh = 0b11,
471}
472
473#[derive(Copy, Clone)]
474#[repr(u8)]
475/// Represents a DMA channel to select, eg when configuring for use with a peripheral.
476/// u8 representation is used to index registers on H7 PAC (And hopefully on future PACs if they
477/// adopt H7's approach)
478pub enum DmaChannel {
479    // H7 calls these Streams. We use the `Channel` name for consistency.
480    #[cfg(feature = "h7")]
481    C0 = 0,
482    C1 = 1,
483    C2 = 2,
484    C3 = 3,
485    C4 = 4,
486    C5 = 5,
487    // todo: Some G0 variants have channels 6 and 7 and DMA1. (And up to 5 channels on DMA2)
488    #[cfg(not(feature = "g0"))]
489    C6 = 6,
490    #[cfg(not(feature = "g0"))]
491    C7 = 7,
492    // todo: Which else have 8? Also, note that some have diff amounts on dma1 vs 2.
493    #[cfg(any(feature = "l5", feature = "g4"))]
494    C8 = 8,
495}
496
497#[derive(Copy, Clone)]
498#[repr(u8)]
499/// Set in CCR.
500/// Can only be set when channel is disabled.
501pub enum Direction {
502    /// DIR = 0 defines typically a peripheral-to-memory transfer
503    ReadFromPeriph = 0,
504    /// DIR = 1 defines typically a memory-to-peripheral transfer.
505    ReadFromMem = 1,
506    MemToMem = 2,
507}
508
509#[derive(Copy, Clone, PartialEq)]
510#[repr(u8)]
511/// Set in CCR.
512/// Can only be set when channel is disabled.
513pub enum Circular {
514    Disabled = 0,
515    Enabled = 1,
516}
517
518#[derive(Copy, Clone)]
519#[repr(u8)]
520/// Peripheral and memory increment mode. (CCR PINC and MINC bits)
521/// Can only be set when channel is disabled.
522pub enum IncrMode {
523    // Can only be set when channel is disabled.
524    Disabled = 0,
525    Enabled = 1,
526}
527
528#[derive(Copy, Clone)]
529#[repr(u8)]
530/// Peripheral and memory increment mode. (CCR PSIZE and MSIZE bits)
531/// Can only be set when channel is disabled.
532pub enum DataSize {
533    S8 = 0b00, // ie 8 bits
534    S16 = 0b01,
535    S32 = 0b10,
536}
537
538#[derive(Copy, Clone)]
539/// Interrupt type. Set in CCR using TEIE, HTIE, and TCIE bits.
540/// Can only be set when channel is disabled.
541pub enum DmaInterrupt {
542    TransferError,
543    HalfTransfer,
544    TransferComplete,
545    #[cfg(feature = "h7")]
546    DirectModeError,
547    #[cfg(feature = "h7")]
548    FifoError,
549}
550
551/// Reduce DRY over channels when configuring a channel's CCR.
552/// We must use a macro here, since match arms balk at the incompatible
553/// types of `CCR1`, `CCR2` etc.
554#[cfg(not(feature = "h7"))]
555macro_rules! set_ccr {
556    ($ccr:expr, $priority:expr, $direction:expr, $circular:expr, $periph_incr:expr, $mem_incr:expr, $periph_size:expr, $mem_size:expr) => {
557        // "The register fields/bits MEM2MEM, PL[1:0], MSIZE[1:0], PSIZE[1:0], MINC, PINC, and DIR
558        // are read-only when EN = 1"
559        let originally_enabled = $ccr.read().en().bit_is_set();
560        if originally_enabled {
561            $ccr.modify(|_, w| w.en().clear_bit());
562            while $ccr.read().en().bit_is_set() {}
563        }
564
565        if let Circular::Enabled = $circular {
566            $ccr.modify(|_, w| w.mem2mem().clear_bit());
567        }
568
569        $ccr.modify(|_, w| unsafe {
570            // – the channel priority
571            w.pl().bits($priority as u8);
572            // – the data transfer direction
573            // This bit [DIR] must be set only in memory-to-peripheral and peripheral-to-memory modes.
574            // 0: read from peripheral
575            w.dir().bit($direction as u8 != 0);
576            // – the circular mode
577            w.circ().bit($circular as u8 != 0);
578            // – the peripheral and memory incremented mode
579            w.pinc().bit($periph_incr as u8 != 0);
580            w.minc().bit($mem_incr as u8 != 0);
581            // – the peripheral and memory data size
582            w.psize().bits($periph_size as u8);
583            w.msize().bits($mem_size as u8);
584            // – the interrupt enable at half and/or full transfer and/or transfer error
585            w.tcie().set_bit();
586            // (See `Step 5` above.)
587            w.en().set_bit()
588        });
589
590        if originally_enabled {
591            $ccr.modify(|_, w| w.en().set_bit());
592            while $ccr.read().en().bit_is_clear() {}
593        }
594    }
595}
596
597/// Reduce DRY over channels when configuring a channel's interrupts.
598#[cfg(not(feature = "h7"))]
599macro_rules! enable_interrupt {
600    ($ccr:expr, $interrupt_type:expr) => {
601        // "It must not be written when the channel is enabled (EN = 1)."
602        let originally_enabled = $ccr.read().en().bit_is_set();
603        if originally_enabled {
604            $ccr.modify(|_, w| w.en().clear_bit());
605            while $ccr.read().en().bit_is_set() {}
606        }
607
608        $ccr.modify(|_, w| match $interrupt_type {
609            DmaInterrupt::TransferError => w.teie().set_bit(),
610            DmaInterrupt::HalfTransfer => w.htie().set_bit(),
611            DmaInterrupt::TransferComplete => w.tcie().set_bit(),
612        });
613
614        if originally_enabled {
615            $ccr.modify(|_, w| w.en().set_bit());
616            while $ccr.read().en().bit_is_clear() {}
617        }
618    };
619}
620
621/// Reduce DRY over channels when configuring a channel's interrupts.
622#[cfg(not(feature = "h7"))]
623macro_rules! disable_interrupt {
624    ($ccr:expr, $interrupt_type:expr) => {
625        // "It must not be written when the channel is disabled (EN = 1)."
626        let originally_disabled = $ccr.read().en().bit_is_set();
627        if originally_disabled {
628            $ccr.modify(|_, w| w.en().clear_bit());
629            while $ccr.read().en().bit_is_set() {}
630        }
631
632        $ccr.modify(|_, w| match $interrupt_type {
633            DmaInterrupt::TransferError => w.teie().clear_bit(),
634            DmaInterrupt::HalfTransfer => w.htie().clear_bit(),
635            DmaInterrupt::TransferComplete => w.tcie().clear_bit(),
636        });
637
638        if originally_disabled {
639            $ccr.modify(|_, w| w.en().set_bit());
640            while $ccr.read().en().bit_is_clear() {}
641        }
642    };
643}
644
645/// This struct is used to pass common (non-peripheral and non-use-specific) data when configuring
646/// a channel.
647#[derive(Clone)]
648pub struct ChannelCfg {
649    /// Channel priority compared to other channels; can be low, medium, high, or very high. Defaults
650    /// to medium.
651    pub priority: Priority,
652    /// Enable or disable circular DMA. If enabled, the transfer continues after reaching the end of
653    /// the buffer, looping to the beginning. A TC interrupt first each time the end is reached, if
654    /// set. Defaults to disabled.
655    pub circular: Circular,
656    /// Whether we increment the peripheral address on data word transfer; generally (and by default)
657    /// disabled.
658    pub periph_incr: IncrMode,
659    /// Whether we increment the buffer address on data word transfer; generally (and by default)
660    /// enabled.
661    pub mem_incr: IncrMode,
662}
663
664impl Default for ChannelCfg {
665    fn default() -> Self {
666        Self {
667            priority: Priority::Medium,
668            circular: Circular::Disabled,
669            // Increment the buffer address, not the peripheral address.
670            periph_incr: IncrMode::Disabled,
671            mem_incr: IncrMode::Enabled,
672        }
673    }
674}
675
676/// Represents a Direct Memory Access (DMA) peripheral.
677pub struct Dma<D> {
678    pub regs: D,
679}
680
681impl<D> Dma<D>
682where
683    D: Deref<Target = dma1::RegisterBlock>,
684{
685    /// Initialize a DMA peripheral, including enabling and resetting
686    /// its RCC peripheral clock.
687    pub fn new(regs: D) -> Self {
688        // todo: Enable RCC for DMA 2 etc!
689        let rcc = unsafe { &(*RCC::ptr()) };
690        cfg_if! {
691            if #[cfg(feature = "f3")] {
692                rcc.ahbenr.modify(|_, w| w.dma1en().set_bit()); // no dmarst on F3.
693            } else if #[cfg(feature = "g0")] {
694                rcc_en_reset!(ahb1, dma, rcc);
695            } else {
696                rcc_en_reset!(ahb1, dma1, rcc);
697            }
698        }
699
700        Self { regs }
701    }
702
703    #[cfg(not(feature = "h7"))] // due to num_data size diff
704    /// Configure a DMA channel. See L4 RM 0394, section 11.4.4. Sets the Transfer Complete
705    /// interrupt. Note that this fn has been (perhaps) depreciated by the standalone fn.
706    pub fn cfg_channel(
707        &mut self,
708        channel: DmaChannel,
709        periph_addr: u32,
710        mem_addr: u32,
711        num_data: u16,
712        direction: Direction,
713        periph_size: DataSize,
714        mem_size: DataSize,
715        cfg: ChannelCfg,
716    ) {
717        cfg_channel(
718            &mut self.regs,
719            channel,
720            periph_addr,
721            mem_addr,
722            num_data,
723            direction,
724            periph_size,
725            mem_size,
726            cfg,
727        )
728    }
729
730    #[cfg(feature = "h7")]
731    /// Configure a DMA channel. See L4 RM 0394, section 11.4.4. Sets the Transfer Complete
732    /// interrupt. Note that this fn has been (perhaps) depreciated by the standalone fn.
733    pub fn cfg_channel(
734        &mut self,
735        channel: DmaChannel,
736        periph_addr: u32,
737        mem_addr: u32,
738        num_data: u32,
739        direction: Direction,
740        periph_size: DataSize,
741        mem_size: DataSize,
742        cfg: ChannelCfg,
743    ) {
744        cfg_channel(
745            &mut self.regs,
746            channel,
747            periph_addr,
748            mem_addr,
749            num_data,
750            direction,
751            periph_size,
752            mem_size,
753            cfg,
754        )
755    }
756
757    #[cfg(feature = "l4")]
758    pub(crate) fn channel_select(&mut self, input: DmaInput) {
759        channel_select(&mut self.regs, input);
760    }
761
762    /// Stop a DMA transfer, if in progress.
763    pub fn stop(&mut self, channel: DmaChannel) {
764        stop_internal(&mut self.regs, channel);
765    }
766
767    /// Clear an interrupt flag.
768    pub fn clear_interrupt(&mut self, channel: DmaChannel, interrupt: DmaInterrupt) {
769        clear_interrupt_internal(&mut self.regs, channel, interrupt);
770    }
771
772    // todo: G0 removed from this fn due to a bug introduced in PAC 0.13
773    #[cfg(not(any(feature = "h7", feature = "g0")))]
774    pub fn transfer_is_complete(&mut self, channel: DmaChannel) -> bool {
775        let isr_val = self.regs.isr.read();
776        match channel {
777            DmaChannel::C1 => isr_val.tcif1().bit_is_set(),
778            DmaChannel::C2 => isr_val.tcif2().bit_is_set(),
779            DmaChannel::C3 => isr_val.tcif3().bit_is_set(),
780            DmaChannel::C4 => isr_val.tcif4().bit_is_set(),
781            DmaChannel::C5 => isr_val.tcif5().bit_is_set(),
782            #[cfg(not(feature = "g0"))]
783            DmaChannel::C6 => isr_val.tcif6().bit_is_set(),
784            #[cfg(not(feature = "g0"))]
785            DmaChannel::C7 => isr_val.tcif7().bit_is_set(),
786            #[cfg(any(feature = "l5", feature = "g4"))]
787            DmaChannel::C8 => isr_val.tcif8().bit_is_set(),
788        }
789    }
790
791    #[cfg(feature = "h7")]
792    pub fn transfer_is_complete(&mut self, channel: DmaChannel) -> bool {
793        match channel {
794            DmaChannel::C0 => self.regs.lisr.read().tcif0().bit_is_set(),
795            DmaChannel::C1 => self.regs.lisr.read().tcif1().bit_is_set(),
796            DmaChannel::C2 => self.regs.lisr.read().tcif2().bit_is_set(),
797            DmaChannel::C3 => self.regs.lisr.read().tcif3().bit_is_set(),
798            DmaChannel::C4 => self.regs.hisr.read().tcif4().bit_is_set(),
799            DmaChannel::C5 => self.regs.hisr.read().tcif5().bit_is_set(),
800            DmaChannel::C6 => self.regs.hisr.read().tcif6().bit_is_set(),
801            DmaChannel::C7 => self.regs.hisr.read().tcif7().bit_is_set(),
802        }
803    }
804
805    /// Enable a specific type of interrupt.
806    pub fn enable_interrupt(&mut self, channel: DmaChannel, interrupt: DmaInterrupt) {
807        enable_interrupt_internal(&mut self.regs, channel, interrupt);
808    }
809
810    /// Disable a specific type of interrupt.
811    /// todo: Non-H7 version too!
812    #[cfg(feature = "h7")]
813    pub fn disable_interrupt(&mut self, channel: DmaChannel, interrupt: DmaInterrupt) {
814        // Can only be set when the channel is disabled.
815        // todo: Is this true for disabling interrupts true, re the channel must be disabled?
816        let cr = &self.regs.st[channel as usize].cr;
817
818        let originally_enabled = cr.read().en().bit_is_set();
819
820        if originally_enabled {
821            cr.modify(|_, w| w.en().clear_bit());
822            while cr.read().en().bit_is_set() {}
823        }
824
825        match interrupt {
826            DmaInterrupt::TransferError => cr.modify(|_, w| w.teie().clear_bit()),
827            DmaInterrupt::HalfTransfer => cr.modify(|_, w| w.htie().clear_bit()),
828            DmaInterrupt::TransferComplete => cr.modify(|_, w| w.tcie().clear_bit()),
829            DmaInterrupt::DirectModeError => cr.modify(|_, w| w.dmeie().clear_bit()),
830            DmaInterrupt::FifoError => self.regs.st[channel as usize]
831                .fcr
832                .modify(|_, w| w.feie().clear_bit()),
833        }
834
835        if originally_enabled {
836            cr.modify(|_, w| w.en().set_bit());
837            while cr.read().en().bit_is_clear() {}
838        }
839    }
840}
841
842/// Configure a DMA channel. See L4 RM 0394, section 11.4.4. Sets the Transfer Complete
843/// interrupt. This is the function called by various module `read_dma` and `write_dma` functions.
844#[cfg(not(feature = "h7"))]
845pub fn cfg_channel<D>(
846    regs: &mut D,
847    channel: DmaChannel,
848    periph_addr: u32,
849    mem_addr: u32,
850    num_data: u16,
851    direction: Direction,
852    periph_size: DataSize,
853    mem_size: DataSize,
854    cfg: ChannelCfg,
855) where
856    D: Deref<Target = dma1::RegisterBlock>,
857{
858    // See the comments in the H7 variant for a description of what's going on.
859
860    unsafe {
861        match channel {
862            DmaChannel::C1 => {
863                cfg_if! {
864                    if #[cfg(any(feature = "f3", feature = "g0"))] {
865                        let cpar = &regs.ch1.par;
866                    } else {
867                        let cpar = &regs.cpar1;
868                    }
869                }
870                cpar.write(|w| w.bits(periph_addr));
871            }
872            DmaChannel::C2 => {
873                cfg_if! {
874                    if #[cfg(any(feature = "f3", feature = "g0"))] {
875                        let cpar = &regs.ch2.par;
876                    } else {
877                        let cpar = &regs.cpar2;
878                    }
879                }
880                cpar.write(|w| w.bits(periph_addr));
881            }
882            DmaChannel::C3 => {
883                cfg_if! {
884                    if #[cfg(any(feature = "f3", feature = "g0"))] {
885                        let cpar = &regs.ch3.par;
886                    } else {
887                        let cpar = &regs.cpar3;
888                    }
889                }
890                cpar.write(|w| w.bits(periph_addr));
891            }
892            DmaChannel::C4 => {
893                cfg_if! {
894                    if #[cfg(any(feature = "f3", feature = "g0"))] {
895                        let cpar = &regs.ch4.par;
896                    } else {
897                        let cpar = &regs.cpar4;
898                    }
899                }
900                cpar.write(|w| w.bits(periph_addr));
901            }
902            DmaChannel::C5 => {
903                cfg_if! {
904                    if #[cfg(any(feature = "f3", feature = "g0"))] {
905                        let cpar = &regs.ch5.par;
906                    } else {
907                        let cpar = &regs.cpar5;
908                    }
909                }
910                cpar.write(|w| w.bits(periph_addr));
911            }
912            #[cfg(not(feature = "g0"))]
913            DmaChannel::C6 => {
914                cfg_if! {
915                    if #[cfg(any(feature = "f3", feature = "g0"))] {
916                        let cpar = &regs.ch6.par;
917                    } else {
918                        let cpar = &regs.cpar6;
919                    }
920                }
921                cpar.write(|w| w.bits(periph_addr));
922            }
923            #[cfg(not(feature = "g0"))]
924            DmaChannel::C7 => {
925                cfg_if! {
926                    if #[cfg(any(feature = "f3", feature = "g0"))] {
927                        let cpar = &regs.ch7.par;
928                    } else {
929                        let cpar = &regs.cpar7;
930                    }
931                }
932                cpar.write(|w| w.bits(periph_addr));
933            }
934            #[cfg(any(feature = "l5", feature = "g4"))]
935            DmaChannel::C8 => {
936                let cpar = &regs.cpar8;
937                cpar.write(|w| w.bits(periph_addr));
938            }
939        }
940    }
941
942    atomic::compiler_fence(Ordering::SeqCst);
943    unsafe {
944        match channel {
945            DmaChannel::C1 => {
946                cfg_if! {
947                    if #[cfg(any(feature = "f3", feature = "g0"))] {
948                        let cmar = &regs.ch1.mar;
949                    } else if #[cfg(feature = "l5")] {
950                        let cmar = &regs.cm0ar1;
951                    } else {
952                        let cmar = &regs.cmar1;
953                    }
954                }
955                cmar.write(|w| w.bits(mem_addr));
956            }
957            DmaChannel::C2 => {
958                cfg_if! {
959                    if #[cfg(any(feature = "f3", feature = "g0"))] {
960                        let cmar = &regs.ch2.mar;
961                    } else if #[cfg(feature = "l5")] {
962                        let cmar = &regs.cm0ar2;
963                    } else {
964                        let cmar = &regs.cmar2;
965                    }
966                }
967                cmar.write(|w| w.bits(mem_addr));
968            }
969            DmaChannel::C3 => {
970                cfg_if! {
971                    if #[cfg(any(feature = "f3", feature = "g0"))] {
972                        let cmar = &regs.ch3.mar;
973                    } else if #[cfg(feature = "l5")] {
974                        let cmar = &regs.cm0ar3;
975                    } else {
976                        let cmar = &regs.cmar3;
977                    }
978                }
979                cmar.write(|w| w.bits(mem_addr));
980            }
981            DmaChannel::C4 => {
982                cfg_if! {
983                    if #[cfg(any(feature = "f3", feature = "g0"))] {
984                        let cmar = &regs.ch4.mar;
985                    } else if #[cfg(feature = "l5")] {
986                        let cmar = &regs.cm0ar4;
987                    } else {
988                        let cmar = &regs.cmar4;
989                    }
990                }
991                cmar.write(|w| w.bits(mem_addr));
992            }
993            DmaChannel::C5 => {
994                cfg_if! {
995                    if #[cfg(any(feature = "f3", feature = "g0"))] {
996                        let cmar = &regs.ch5.mar;
997                    } else if #[cfg(feature = "l5")] {
998                        let cmar = &regs.cm0ar5;
999                    } else {
1000                        let cmar = &regs.cmar5;
1001                    }
1002                }
1003                cmar.write(|w| w.bits(mem_addr));
1004            }
1005            #[cfg(not(feature = "g0"))]
1006            DmaChannel::C6 => {
1007                cfg_if! {
1008                    if #[cfg(any(feature = "f3", feature = "g0"))] {
1009                        let cmar = &regs.ch6.mar;
1010                    } else if #[cfg(feature = "l5")] {
1011                        let cmar = &regs.cm0ar6;
1012                    } else {
1013                        let cmar = &regs.cmar6;
1014                    }
1015                }
1016                cmar.write(|w| w.bits(mem_addr));
1017            }
1018            #[cfg(not(feature = "g0"))]
1019            DmaChannel::C7 => {
1020                cfg_if! {
1021                    if #[cfg(any(feature = "f3", feature = "g0"))] {
1022                        let cmar = &regs.ch7.mar;
1023                    } else if #[cfg(feature = "l5")] {
1024                        let cmar = &regs.cm0ar7;
1025                    } else {
1026                        let cmar = &regs.cmar7;
1027                    }
1028                }
1029                cmar.write(|w| w.bits(mem_addr));
1030            }
1031            #[cfg(any(feature = "l5", feature = "g4"))]
1032            DmaChannel::C8 => {
1033                #[cfg(feature = "l5")]
1034                let cmar = &regs.cm0ar8;
1035                #[cfg(feature = "g4")]
1036                let cmar = &regs.cmar8;
1037                cmar.write(|w| w.bits(mem_addr));
1038            }
1039        }
1040    }
1041
1042    #[cfg(any(feature = "l5", feature = "wl"))]
1043    let num_data = num_data as u32;
1044
1045    #[cfg(not(feature = "l5"))] // todo: PAC ommission? ndt fields missing for diff ndt regs.
1046    unsafe {
1047        match channel {
1048            DmaChannel::C1 => {
1049                cfg_if! {
1050                    if #[cfg(any(feature = "f3", feature = "g0"))] {
1051                        let cndtr = &regs.ch1.ndtr;
1052                    } else {
1053                        let cndtr = &regs.cndtr1;
1054                    }
1055                }
1056                cndtr.write(|w| w.ndt().bits(num_data));
1057            }
1058            DmaChannel::C2 => {
1059                cfg_if! {
1060                    if #[cfg(any(feature = "f3", feature = "g0"))] {
1061                        let cndtr = &regs.ch2.ndtr;
1062                    } else {
1063                        let cndtr = &regs.cndtr2;
1064                    }
1065                }
1066                cndtr.write(|w| w.ndt().bits(num_data));
1067            }
1068            DmaChannel::C3 => {
1069                cfg_if! {
1070                    if #[cfg(any(feature = "f3", feature = "g0"))] {
1071                        let cndtr = &regs.ch3.ndtr;
1072                    } else {
1073                        let cndtr = &regs.cndtr3;
1074                    }
1075                }
1076                cndtr.write(|w| w.ndt().bits(num_data));
1077            }
1078            DmaChannel::C4 => {
1079                cfg_if! {
1080                    if #[cfg(any(feature = "f3", feature = "g0"))] {
1081                        let cndtr = &regs.ch4.ndtr;
1082                    } else {
1083                        let cndtr = &regs.cndtr4;
1084                    }
1085                }
1086                cndtr.write(|w| w.ndt().bits(num_data));
1087            }
1088            DmaChannel::C5 => {
1089                cfg_if! {
1090                    if #[cfg(any(feature = "f3", feature = "g0"))] {
1091                        let cndtr = &regs.ch5.ndtr;
1092                    } else {
1093                        let cndtr = &regs.cndtr5;
1094                    }
1095                }
1096                cndtr.write(|w| w.ndt().bits(num_data));
1097            }
1098            #[cfg(not(feature = "g0"))]
1099            DmaChannel::C6 => {
1100                cfg_if! {
1101                    if #[cfg(any(feature = "f3", feature = "g0"))] {
1102                        let cndtr = &regs.ch6.ndtr;
1103                    } else {
1104                        let cndtr = &regs.cndtr6;
1105                    }
1106                }
1107                cndtr.write(|w| w.ndt().bits(num_data));
1108            }
1109            #[cfg(not(feature = "g0"))]
1110            DmaChannel::C7 => {
1111                cfg_if! {
1112                    if #[cfg(any(feature = "f3", feature = "g0"))] {
1113                        let cndtr = &regs.ch7.ndtr;
1114                    } else {
1115                        let cndtr = &regs.cndtr7;
1116                    }
1117                }
1118                cndtr.write(|w| w.ndt().bits(num_data));
1119            }
1120            #[cfg(any(feature = "l5", feature = "g4"))]
1121            DmaChannel::C8 => {
1122                let cndtr = &regs.cndtr8;
1123                cndtr.write(|w| w.ndt().bits(num_data));
1124            }
1125        }
1126    }
1127
1128    match channel {
1129        DmaChannel::C1 => {
1130            cfg_if! {
1131                if #[cfg(any(feature = "f3", feature = "g0"))] {
1132                    let ccr = &regs.ch1.cr;
1133                } else {
1134                    let ccr = &regs.ccr1;
1135                }
1136            }
1137            set_ccr!(
1138                ccr,
1139                cfg.priority,
1140                direction,
1141                cfg.circular,
1142                cfg.periph_incr,
1143                cfg.mem_incr,
1144                periph_size,
1145                mem_size
1146            );
1147        }
1148        DmaChannel::C2 => {
1149            cfg_if! {
1150                if #[cfg(any(feature = "f3", feature = "g0"))] {
1151                    let ccr = &regs.ch2.cr;
1152                } else {
1153                    let ccr = &regs.ccr2;
1154                }
1155            }
1156            set_ccr!(
1157                ccr,
1158                cfg.priority,
1159                direction,
1160                cfg.circular,
1161                cfg.periph_incr,
1162                cfg.mem_incr,
1163                periph_size,
1164                mem_size
1165            );
1166        }
1167        DmaChannel::C3 => {
1168            cfg_if! {
1169                if #[cfg(any(feature = "f3", feature = "g0"))] {
1170                    let ccr = &regs.ch3.cr;
1171                } else {
1172                    let ccr = &regs.ccr3;
1173                }
1174            }
1175            set_ccr!(
1176                ccr,
1177                cfg.priority,
1178                direction,
1179                cfg.circular,
1180                cfg.periph_incr,
1181                cfg.mem_incr,
1182                periph_size,
1183                mem_size
1184            );
1185        }
1186        DmaChannel::C4 => {
1187            cfg_if! {
1188                if #[cfg(any(feature = "f3", feature = "g0"))] {
1189                    let ccr = &regs.ch4.cr;
1190                } else {
1191                    let ccr = &regs.ccr4;
1192                }
1193            }
1194            set_ccr!(
1195                ccr,
1196                cfg.priority,
1197                direction,
1198                cfg.circular,
1199                cfg.periph_incr,
1200                cfg.mem_incr,
1201                periph_size,
1202                mem_size
1203            );
1204        }
1205        DmaChannel::C5 => {
1206            cfg_if! {
1207                if #[cfg(any(feature = "f3", feature = "g0"))] {
1208                    let ccr = &regs.ch5.cr;
1209                } else {
1210                    let ccr = &regs.ccr5;
1211                }
1212            }
1213            set_ccr!(
1214                ccr,
1215                cfg.priority,
1216                direction,
1217                cfg.circular,
1218                cfg.periph_incr,
1219                cfg.mem_incr,
1220                periph_size,
1221                mem_size
1222            );
1223        }
1224        #[cfg(not(feature = "g0"))]
1225        DmaChannel::C6 => {
1226            cfg_if! {
1227                if #[cfg(any(feature = "f3", feature = "g0"))] {
1228                    let ccr = &regs.ch6.cr;
1229                } else {
1230                    let ccr = &regs.ccr6;
1231                }
1232            }
1233            set_ccr!(
1234                ccr,
1235                cfg.priority,
1236                direction,
1237                cfg.circular,
1238                cfg.periph_incr,
1239                cfg.mem_incr,
1240                periph_size,
1241                mem_size
1242            );
1243        }
1244        #[cfg(not(feature = "g0"))]
1245        DmaChannel::C7 => {
1246            cfg_if! {
1247                if #[cfg(any(feature = "f3", feature = "g0"))] {
1248                    let ccr = &regs.ch7.cr;
1249                } else {
1250                    let ccr = &regs.ccr7;
1251                }
1252            }
1253            set_ccr!(
1254                ccr,
1255                cfg.priority,
1256                direction,
1257                cfg.circular,
1258                cfg.periph_incr,
1259                cfg.mem_incr,
1260                periph_size,
1261                mem_size
1262            );
1263        }
1264        #[cfg(any(feature = "l5", feature = "g4"))]
1265        DmaChannel::C8 => {
1266            let ccr = &regs.ccr8;
1267            set_ccr!(
1268                ccr,
1269                cfg.priority,
1270                direction,
1271                cfg.circular,
1272                cfg.periph_incr,
1273                cfg.mem_incr,
1274                periph_size,
1275                mem_size
1276            );
1277        }
1278    }
1279}
1280
1281/// Configure a DMA channel. See L4 RM 0394, section 11.4.4. Sets the Transfer Complete
1282/// interrupt. This is the function called by various module `read_dma` and `write_dma` functions.
1283#[cfg(feature = "h7")]
1284pub fn cfg_channel<D>(
1285    regs: &mut D,
1286    channel: DmaChannel,
1287    periph_addr: u32,
1288    mem_addr: u32,
1289    num_data: u32,
1290    direction: Direction,
1291    periph_size: DataSize,
1292    mem_size: DataSize,
1293    cfg: ChannelCfg,
1294) where
1295    D: Deref<Target = dma1::RegisterBlock>,
1296{
1297    // todo: The H7 sections are different, but we consolidated the comments. Figure out
1298    // todo what's different and fix it by following the steps
1299
1300    regs.st[channel as usize]
1301        .cr
1302        .modify(|_, w| w.en().clear_bit());
1303    while regs.st[channel as usize].cr.read().en().bit_is_set() {}
1304
1305    // H743 RM Section 15.3.19 The following sequence is needed to configure a DMA stream x:
1306    // 1. Set the peripheral register address in the DMA_CPARx register.
1307    // The data is moved from/to this address to/from the memory after the peripheral event,
1308    // or after the channel is enabled in memory-to-memory mode.
1309    regs.st[channel as usize]
1310        .par
1311        .write(|w| unsafe { w.bits(periph_addr) });
1312
1313    atomic::compiler_fence(Ordering::SeqCst);
1314
1315    // 2. Set the memory address in the DMA_CMARx register.
1316    // The data is written to/read from the memory after the peripheral event or after the
1317    // channel is enabled in memory-to-memory mode.
1318    regs.st[channel as usize]
1319        .m0ar
1320        .write(|w| unsafe { w.bits(mem_addr) });
1321
1322    // todo: m1ar too, if in double-buffer mode.
1323
1324    // 3. Configure the total number of data to transfer in the DMA_CNDTRx register.
1325    // After each data transfer, this value is decremented.
1326    regs.st[channel as usize]
1327        .ndtr
1328        .write(|w| unsafe { w.bits(num_data) });
1329
1330    // 4. Configure the parameters listed below in the DMA_CCRx register:
1331    // (These are listed below by their corresponding reg write code)
1332
1333    // todo: See note about sep reg writes to disable channel, and when you need to do this.
1334
1335    // 5. Activate the channel by setting the EN bit in the DMA_CCRx register.
1336    // A channel, as soon as enabled, may serve any DMA request from the peripheral connected
1337    // to this channel, or may start a memory-to-memory block transfer.
1338    // Note: The two last steps of the channel configuration procedure may be merged into a single
1339    // access to the DMA_CCRx register, to configure and enable the channel.
1340    // When a channel is enabled and still active (not completed), the software must perform two
1341    // separate write accesses to the DMA_CCRx register, to disable the channel, then to
1342    // reprogram the channel for another next block transfer.
1343    // Some fields of the DMA_CCRx register are read-only when the EN bit is set to 1
1344
1345    // (later): The circular mode must not be used in memory-to-memory mode. Before enabling a
1346    // channel in circular mode (CIRC = 1), the software must clear the MEM2MEM bit of the
1347    // DMA_CCRx register. When the circular mode is activated, the amount of data to transfer is
1348    // automatically reloaded with the initial value programmed during the channel configuration
1349    // phase, and the DMA requests continue to be served
1350
1351    // (See remainder of steps in `set_ccr()!` macro.
1352
1353    // todo: Let user set mem2mem mode?
1354
1355    // See the [Embedonomicon section on DMA](https://docs.rust-embedded.org/embedonomicon/dma.html)
1356    // for info on why we use `compiler_fence` here:
1357    // "We use Ordering::Release to prevent all preceding memory operations from being moved
1358    // after [starting DMA], which performs a volatile write."
1359
1360    let cr = &regs.st[channel as usize].cr;
1361
1362    let originally_enabled = cr.read().en().bit_is_set();
1363    if originally_enabled {
1364        cr.modify(|_, w| w.en().clear_bit());
1365        while cr.read().en().bit_is_set() {}
1366    }
1367
1368    cr.modify(|_, w| unsafe {
1369        // – the channel priority
1370        w.pl().bits(cfg.priority as u8);
1371        // – the data transfer direction
1372        // This bit [DIR] must be set only in memory-to-peripheral and peripheral-to-memory modes.
1373        // 0: read from peripheral
1374        w.dir().bits(direction as u8);
1375        // – the circular mode
1376        w.circ().bit(cfg.circular as u8 != 0);
1377        // – the peripheral and memory incremented mode
1378        w.pinc().bit(cfg.periph_incr as u8 != 0);
1379        w.minc().bit(cfg.mem_incr as u8 != 0);
1380        // – the peripheral and memory data size
1381        w.psize().bits(periph_size as u8);
1382        w.msize().bits(mem_size as u8);
1383        // – the interrupt enable at half and/or full transfer and/or transfer error
1384        w.tcie().set_bit();
1385        // (See `Step 5` above.)
1386        w.en().set_bit()
1387    });
1388
1389    if originally_enabled {
1390        cr.modify(|_, w| w.en().set_bit());
1391        while cr.read().en().bit_is_clear() {}
1392    }
1393}
1394
1395/// Stop a DMA transfer, if in progress.
1396#[cfg(not(feature = "h7"))]
1397fn stop_internal<D>(regs: &mut D, channel: DmaChannel)
1398where
1399    D: Deref<Target = dma1::RegisterBlock>,
1400{
1401    // L4 RM:
1402    // Once the software activates a channel, it waits for the completion of the programmed
1403    // transfer. The DMA controller is not able to resume an aborted active channel with a possible
1404    // suspended bus transfer.
1405    // To correctly stop and disable a channel, the software clears the EN bit of the DMA_CCRx
1406    // register.
1407
1408    match channel {
1409        DmaChannel::C1 => {
1410            cfg_if! {
1411                if #[cfg(any(feature = "f3", feature = "g0"))] {
1412                    let ccr = &regs.ch1.cr;
1413                } else {
1414                    let ccr = &regs.ccr1;
1415                }
1416            }
1417            ccr.modify(|_, w| w.en().clear_bit());
1418            while ccr.read().en().bit_is_set() {}
1419        }
1420        DmaChannel::C2 => {
1421            cfg_if! {
1422                if #[cfg(any(feature = "f3", feature = "g0"))] {
1423                    let ccr = &regs.ch2.cr;
1424                } else {
1425                    let ccr = &regs.ccr2;
1426                }
1427            }
1428            ccr.modify(|_, w| w.en().clear_bit());
1429            while ccr.read().en().bit_is_set() {}
1430        }
1431        DmaChannel::C3 => {
1432            cfg_if! {
1433                if #[cfg(any(feature = "f3", feature = "g0"))] {
1434                    let ccr = &regs.ch3.cr;
1435                } else {
1436                    let ccr = &regs.ccr3;
1437                }
1438            }
1439            ccr.modify(|_, w| w.en().clear_bit());
1440            while ccr.read().en().bit_is_set() {}
1441        }
1442        DmaChannel::C4 => {
1443            cfg_if! {
1444                if #[cfg(any(feature = "f3", feature = "g0"))] {
1445                    let ccr = &regs.ch4.cr;
1446                } else {
1447                    let ccr = &regs.ccr4;
1448                }
1449            }
1450            ccr.modify(|_, w| w.en().clear_bit());
1451            while ccr.read().en().bit_is_set() {}
1452        }
1453        DmaChannel::C5 => {
1454            cfg_if! {
1455                if #[cfg(any(feature = "f3", feature = "g0"))] {
1456                    let ccr = &regs.ch5.cr;
1457                } else {
1458                    let ccr = &regs.ccr5;
1459                }
1460            }
1461            ccr.modify(|_, w| w.en().clear_bit());
1462            while ccr.read().en().bit_is_set() {}
1463        }
1464        #[cfg(not(feature = "g0"))]
1465        DmaChannel::C6 => {
1466            cfg_if! {
1467                if #[cfg(any(feature = "f3", feature = "g0"))] {
1468                    let ccr = &regs.ch6.cr;
1469                } else {
1470                    let ccr = &regs.ccr6;
1471                }
1472            }
1473            ccr.modify(|_, w| w.en().clear_bit());
1474            while ccr.read().en().bit_is_set() {}
1475        }
1476        #[cfg(not(feature = "g0"))]
1477        DmaChannel::C7 => {
1478            cfg_if! {
1479                if #[cfg(any(feature = "f3", feature = "g0"))] {
1480                    let ccr = &regs.ch7.cr;
1481                } else {
1482                    let ccr = &regs.ccr7;
1483                }
1484            }
1485            ccr.modify(|_, w| w.en().clear_bit());
1486            while ccr.read().en().bit_is_set() {}
1487        }
1488        #[cfg(any(feature = "l5", feature = "g4"))]
1489        DmaChannel::C8 => {
1490            let ccr = &regs.ccr8;
1491            ccr.modify(|_, w| w.en().clear_bit());
1492            while ccr.read().en().bit_is_set() {}
1493        }
1494    };
1495
1496    // The software secures that no pending request from the peripheral is served by the
1497    // DMA controller before the transfer completion.
1498    // todo?
1499
1500    // The software waits for the transfer complete or transfer error interrupt.
1501    // (Handed by calling code)
1502
1503    // (todo: set ifcr.cficx bit to clear all interrupts?)
1504
1505    // When a channel transfer error occurs, the EN bit of the DMA_CCRx register is cleared by
1506    // hardware. This EN bit can not be set again by software to re-activate the channel x, until the
1507    // TEIFx bit of the DMA_ISR register is set
1508}
1509
1510/// Stop a DMA transfer, if in progress.
1511#[cfg(feature = "h7")]
1512fn stop_internal<D>(regs: &mut D, channel: DmaChannel)
1513where
1514    D: Deref<Target = dma1::RegisterBlock>,
1515{
1516    // L4 RM:
1517    // Once the software activates a channel, it waits for the completion of the programmed
1518    // transfer. The DMA controller is not able to resume an aborted active channel with a possible
1519    // suspended bus transfer.
1520    // To correctly stop and disable a channel, the software clears the EN bit of the DMA_CCRx
1521    // register.
1522
1523    // The software secures that no pending request from the peripheral is served by the
1524    // DMA controller before the transfer completion.
1525    // todo?
1526
1527    let cr = &regs.st[channel as usize].cr;
1528    cr.modify(|_, w| w.en().clear_bit());
1529    while cr.read().en().bit_is_set() {}
1530
1531    // The software waits for the transfer complete or transfer error interrupt.
1532    // (Handed by calling code)
1533
1534    // (todo: set ifcr.cficx bit to clear all interrupts?)
1535
1536    // When a channel transfer error occurs, the EN bit of the DMA_CCRx register is cleared by
1537    // hardware. This EN bit can not be set again by software to re-activate the channel x, until the
1538    // TEIFx bit of the DMA_ISR register is set
1539}
1540
1541/// Stop a DMA transfer, if in progress.
1542pub fn stop(periph: DmaPeriph, channel: DmaChannel) {
1543    match periph {
1544        DmaPeriph::Dma1 => {
1545            let mut regs = unsafe { &(*DMA1::ptr()) };
1546            stop_internal(&mut regs, channel);
1547        }
1548        #[cfg(not(any(feature = "f3x4", feature = "g0", feature = "wb")))]
1549        DmaPeriph::Dma2 => {
1550            let mut regs = unsafe { &(*pac::DMA2::ptr()) };
1551            stop_internal(&mut regs, channel);
1552        }
1553    }
1554}
1555
1556fn clear_interrupt_internal<D>(regs: &mut D, channel: DmaChannel, interrupt: DmaInterrupt)
1557where
1558    D: Deref<Target = dma1::RegisterBlock>,
1559{
1560    cfg_if! {
1561        if #[cfg(any(feature = "g4", feature = "wl"))] {
1562            regs.ifcr.write(|w| match channel {
1563                DmaChannel::C1 => match interrupt {
1564                    DmaInterrupt::TransferError => w.teif1().set_bit(),
1565                    DmaInterrupt::HalfTransfer => w.htif1().set_bit(),
1566                    DmaInterrupt::TransferComplete => w.tcif1().set_bit(),
1567                }
1568                DmaChannel::C2 => match interrupt {
1569                    DmaInterrupt::TransferError => w.teif2().set_bit(),
1570                    DmaInterrupt::HalfTransfer => w.htif2().set_bit(),
1571                    DmaInterrupt::TransferComplete => w.tcif2().set_bit(),
1572                }
1573                DmaChannel::C3 => match interrupt {
1574                    DmaInterrupt::TransferError => w.teif3().set_bit(),
1575                    DmaInterrupt::HalfTransfer => w.htif3().set_bit(),
1576                    DmaInterrupt::TransferComplete => w.tcif3().set_bit(),
1577                }
1578                DmaChannel::C4 => match interrupt {
1579                    DmaInterrupt::TransferError => w.teif4().set_bit(),
1580                    DmaInterrupt::HalfTransfer => w.htif4().set_bit(),
1581                    DmaInterrupt::TransferComplete => w.tcif4().set_bit(),
1582                }
1583                DmaChannel::C5 => match interrupt {
1584                    DmaInterrupt::TransferError => w.teif5().set_bit(),
1585                    DmaInterrupt::HalfTransfer => w.htif5().set_bit(),
1586                    DmaInterrupt::TransferComplete => w.tcif5().set_bit(),
1587                }
1588                DmaChannel::C6 => match interrupt {
1589                    DmaInterrupt::TransferError => w.teif6().set_bit(),
1590                    DmaInterrupt::HalfTransfer => w.htif6().set_bit(),
1591                    DmaInterrupt::TransferComplete => w.tcif6().set_bit(),
1592                }
1593                DmaChannel::C7 => match interrupt {
1594                    DmaInterrupt::TransferError => w.teif7().set_bit(),
1595                    DmaInterrupt::HalfTransfer => w.htif7().set_bit(),
1596                    DmaInterrupt::TransferComplete => w.tcif7().set_bit(),
1597                }
1598                #[cfg(not(feature = "wl"))]
1599                DmaChannel::C8 => match interrupt {
1600                    DmaInterrupt::TransferError => w.teif8().set_bit(),
1601                    DmaInterrupt::HalfTransfer => w.htif8().set_bit(),
1602                    DmaInterrupt::TransferComplete => w.tcif8().set_bit(),
1603                }
1604            });
1605        } else if #[cfg(feature = "h7")] {
1606            match channel {
1607                DmaChannel::C0 => match interrupt {
1608                    DmaInterrupt::TransferError => regs.lifcr.write(|w| w.cteif0().set_bit()),
1609                    DmaInterrupt::HalfTransfer => regs.lifcr.write(|w| w.chtif0().set_bit()),
1610                    DmaInterrupt::TransferComplete => regs.lifcr.write(|w| w.ctcif0().set_bit()),
1611                    DmaInterrupt::DirectModeError => regs.lifcr.write(|w| w.cdmeif0().set_bit()),
1612                    DmaInterrupt::FifoError => regs.lifcr.write(|w| w.cfeif0().set_bit()),
1613                }
1614                DmaChannel::C1 => match interrupt {
1615                    DmaInterrupt::TransferError => regs.lifcr.write(|w| w.cteif1().set_bit()),
1616                    DmaInterrupt::HalfTransfer => regs.lifcr.write(|w| w.chtif1().set_bit()),
1617                    DmaInterrupt::TransferComplete => regs.lifcr.write(|w| w.ctcif1().set_bit()),
1618                    DmaInterrupt::DirectModeError => regs.lifcr.write(|w| w.cdmeif1().set_bit()),
1619                    DmaInterrupt::FifoError => regs.lifcr.write(|w| w.cfeif1().set_bit()),
1620                }
1621                DmaChannel::C2 => match interrupt {
1622                    DmaInterrupt::TransferError => regs.lifcr.write(|w| w.cteif2().set_bit()),
1623                    DmaInterrupt::HalfTransfer => regs.lifcr.write(|w| w.chtif2().set_bit()),
1624                    DmaInterrupt::TransferComplete => regs.lifcr.write(|w| w.ctcif2().set_bit()),
1625                    DmaInterrupt::DirectModeError => regs.lifcr.write(|w| w.cdmeif2().set_bit()),
1626                    DmaInterrupt::FifoError => regs.lifcr.write(|w| w.cfeif2().set_bit()),
1627                }
1628                DmaChannel::C3 => match interrupt {
1629                    DmaInterrupt::TransferError => regs.lifcr.write(|w| w.cteif3().set_bit()),
1630                    DmaInterrupt::HalfTransfer => regs.lifcr.write(|w| w.chtif3().set_bit()),
1631                    DmaInterrupt::TransferComplete => regs.lifcr.write(|w| w.ctcif3().set_bit()),
1632                    DmaInterrupt::DirectModeError => regs.lifcr.write(|w| w.cdmeif3().set_bit()),
1633                    DmaInterrupt::FifoError => regs.lifcr.write(|w| w.cfeif3().set_bit()),
1634                }
1635                DmaChannel::C4 => match interrupt {
1636                    DmaInterrupt::TransferError => regs.hifcr.write(|w| w.cteif4().set_bit()),
1637                    DmaInterrupt::HalfTransfer => regs.hifcr.write(|w| w.chtif4().set_bit()),
1638                    DmaInterrupt::TransferComplete => regs.hifcr.write(|w| w.ctcif4().set_bit()),
1639                    DmaInterrupt::DirectModeError => regs.hifcr.write(|w| w.cdmeif4().set_bit()),
1640                    DmaInterrupt::FifoError => regs.hifcr.write(|w| w.cfeif4().set_bit()),
1641                }
1642                DmaChannel::C5 => match interrupt {
1643                    DmaInterrupt::TransferError => regs.hifcr.write(|w| w.cteif5().set_bit()),
1644                    DmaInterrupt::HalfTransfer => regs.hifcr.write(|w| w.chtif5().set_bit()),
1645                    DmaInterrupt::TransferComplete => regs.hifcr.write(|w| w.ctcif5().set_bit()),
1646                    DmaInterrupt::DirectModeError => regs.hifcr.write(|w| w.cdmeif5().set_bit()),
1647                    DmaInterrupt::FifoError => regs.hifcr.write(|w| w.cfeif5().set_bit()),
1648                }
1649                DmaChannel::C6 => match interrupt {
1650                    DmaInterrupt::TransferError => regs.hifcr.write(|w| w.cteif6().set_bit()),
1651                    DmaInterrupt::HalfTransfer => regs.hifcr.write(|w| w.chtif6().set_bit()),
1652                    DmaInterrupt::TransferComplete => regs.hifcr.write(|w| w.ctcif6().set_bit()),
1653                    DmaInterrupt::DirectModeError => regs.hifcr.write(|w| w.cdmeif6().set_bit()),
1654                    DmaInterrupt::FifoError => regs.hifcr.write(|w| w.cfeif6().set_bit()),
1655                }
1656                DmaChannel::C7 => match interrupt {
1657                    DmaInterrupt::TransferError => regs.hifcr.write(|w| w.cteif7().set_bit()),
1658                    DmaInterrupt::HalfTransfer => regs.hifcr.write(|w| w.chtif7().set_bit()),
1659                    DmaInterrupt::TransferComplete => regs.hifcr.write(|w| w.ctcif7().set_bit()),
1660                    DmaInterrupt::DirectModeError => regs.hifcr.write(|w| w.cdmeif7().set_bit()),
1661                    DmaInterrupt::FifoError => regs.hifcr.write(|w| w.cfeif7().set_bit()),
1662                }
1663            }
1664            // todo: G0 PAC 0.14 had a reversion where these flags used to work, but now don't.
1665        } else if #[cfg(not(feature = "g0"))] {
1666            regs.ifcr.write(|w| match channel {
1667                DmaChannel::C1 => match interrupt {
1668                    DmaInterrupt::TransferError => w.cteif1().set_bit(),
1669                    DmaInterrupt::HalfTransfer => w.chtif1().set_bit(),
1670                    DmaInterrupt::TransferComplete => w.ctcif1().set_bit(),
1671                }
1672                DmaChannel::C2 => match interrupt {
1673                    DmaInterrupt::TransferError => w.cteif2().set_bit(),
1674                    DmaInterrupt::HalfTransfer => w.chtif2().set_bit(),
1675                    DmaInterrupt::TransferComplete => w.ctcif2().set_bit(),
1676                }
1677                DmaChannel::C3 => match interrupt {
1678                    DmaInterrupt::TransferError => w.cteif3().set_bit(),
1679                    DmaInterrupt::HalfTransfer => w.chtif3().set_bit(),
1680                    DmaInterrupt::TransferComplete => w.ctcif3().set_bit(),
1681                }
1682                DmaChannel::C4 => match interrupt {
1683                    DmaInterrupt::TransferError => w.cteif4().set_bit(),
1684                    DmaInterrupt::HalfTransfer => w.chtif4().set_bit(),
1685                    DmaInterrupt::TransferComplete => w.ctcif4().set_bit(),
1686                }
1687                DmaChannel::C5 => match interrupt {
1688                    DmaInterrupt::TransferError => w.cteif5().set_bit(),
1689                    DmaInterrupt::HalfTransfer => w.chtif5().set_bit(),
1690                    DmaInterrupt::TransferComplete => w.ctcif5().set_bit(),
1691                }
1692                #[cfg(not(feature = "g0"))]
1693                DmaChannel::C6 => match interrupt {
1694                    DmaInterrupt::TransferError => w.cteif6().set_bit(),
1695                    DmaInterrupt::HalfTransfer => w.chtif6().set_bit(),
1696                    DmaInterrupt::TransferComplete => w.ctcif6().set_bit(),
1697                }
1698                #[cfg(not(feature = "g0"))]
1699                DmaChannel::C7 => match interrupt {
1700                    DmaInterrupt::TransferError => w.cteif7().set_bit(),
1701                    DmaInterrupt::HalfTransfer => w.chtif7().set_bit(),
1702                    DmaInterrupt::TransferComplete => w.ctcif7().set_bit(),
1703                }
1704                #[cfg(any(feature = "l5", feature = "g4"))]
1705                DmaChannel::C8 => match interrupt {
1706                    DmaInterrupt::TransferError => w.cteif8().set_bit(),
1707                    DmaInterrupt::HalfTransfer => w.chtif8().set_bit(),
1708                    DmaInterrupt::TransferComplete => w.ctcif8().set_bit(),
1709                }
1710            });
1711        }
1712    }
1713}
1714
1715/// Enable an interrupt.
1716#[cfg(not(feature = "h7"))]
1717fn enable_interrupt_internal<D>(regs: &mut D, channel: DmaChannel, interrupt: DmaInterrupt)
1718where
1719    D: Deref<Target = dma1::RegisterBlock>,
1720{
1721    // Can only be set when the channel is disabled.
1722    match channel {
1723        DmaChannel::C1 => {
1724            cfg_if! {
1725                if #[cfg(any(feature = "f3", feature = "g0"))] {
1726                    let ccr = &regs.ch1.cr;
1727                } else {
1728                    let ccr = &regs.ccr1;
1729                }
1730            }
1731            enable_interrupt!(ccr, interrupt);
1732        }
1733        DmaChannel::C2 => {
1734            cfg_if! {
1735                if #[cfg(any(feature = "f3", feature = "g0"))] {
1736                    let ccr = &regs.ch2.cr;
1737                } else {
1738                    let ccr = &regs.ccr2;
1739                }
1740            }
1741            enable_interrupt!(ccr, interrupt);
1742        }
1743        DmaChannel::C3 => {
1744            cfg_if! {
1745                if #[cfg(any(feature = "f3", feature = "g0"))] {
1746                    let ccr = &regs.ch3.cr;
1747                } else {
1748                    let ccr = &regs.ccr3;
1749                }
1750            }
1751            enable_interrupt!(ccr, interrupt);
1752        }
1753        DmaChannel::C4 => {
1754            cfg_if! {
1755                if #[cfg(any(feature = "f3", feature = "g0"))] {
1756                    let ccr = &regs.ch4.cr;
1757                } else {
1758                    let ccr = &regs.ccr4;
1759                }
1760            }
1761            enable_interrupt!(ccr, interrupt);
1762        }
1763        DmaChannel::C5 => {
1764            cfg_if! {
1765                if #[cfg(any(feature = "f3", feature = "g0"))] {
1766                    let ccr = &regs.ch5.cr;
1767                } else {
1768                    let ccr = &regs.ccr5;
1769                }
1770            }
1771            enable_interrupt!(ccr, interrupt);
1772        }
1773        #[cfg(not(feature = "g0"))]
1774        DmaChannel::C6 => {
1775            cfg_if! {
1776                if #[cfg(any(feature = "f3", feature = "g0"))] {
1777                    let ccr = &regs.ch6.cr;
1778                } else {
1779                    let ccr = &regs.ccr6;
1780                }
1781            }
1782            enable_interrupt!(ccr, interrupt);
1783        }
1784        #[cfg(not(feature = "g0"))]
1785        DmaChannel::C7 => {
1786            cfg_if! {
1787                if #[cfg(any(feature = "f3", feature = "g0"))] {
1788                    let ccr = &regs.ch7.cr;
1789                } else {
1790                    let ccr = &regs.ccr7;
1791                }
1792            }
1793            enable_interrupt!(ccr, interrupt);
1794        }
1795        #[cfg(any(feature = "l5", feature = "g4"))]
1796        DmaChannel::C8 => {
1797            let ccr = &regs.ccr8;
1798            enable_interrupt!(ccr, interrupt);
1799        }
1800    };
1801}
1802
1803/// Disable an interrupt.
1804#[cfg(not(feature = "h7"))]
1805fn disable_interrupt_internal<D>(regs: &mut D, channel: DmaChannel, interrupt: DmaInterrupt)
1806where
1807    D: Deref<Target = dma1::RegisterBlock>,
1808{
1809    // Can only be set when the channel is disabled.
1810    match channel {
1811        DmaChannel::C1 => {
1812            cfg_if! {
1813                if #[cfg(any(feature = "f3", feature = "g0"))] {
1814                    let ccr = &regs.ch1.cr;
1815                } else {
1816                    let ccr = &regs.ccr1;
1817                }
1818            }
1819            disable_interrupt!(ccr, interrupt);
1820        }
1821        DmaChannel::C2 => {
1822            cfg_if! {
1823                if #[cfg(any(feature = "f3", feature = "g0"))] {
1824                    let ccr = &regs.ch2.cr;
1825                } else {
1826                    let ccr = &regs.ccr2;
1827                }
1828            }
1829            disable_interrupt!(ccr, interrupt);
1830        }
1831        DmaChannel::C3 => {
1832            cfg_if! {
1833                if #[cfg(any(feature = "f3", feature = "g0"))] {
1834                    let ccr = &regs.ch3.cr;
1835                } else {
1836                    let ccr = &regs.ccr3;
1837                }
1838            }
1839            disable_interrupt!(ccr, interrupt);
1840        }
1841        DmaChannel::C4 => {
1842            cfg_if! {
1843                if #[cfg(any(feature = "f3", feature = "g0"))] {
1844                    let ccr = &regs.ch4.cr;
1845                } else {
1846                    let ccr = &regs.ccr4;
1847                }
1848            }
1849            disable_interrupt!(ccr, interrupt);
1850        }
1851        DmaChannel::C5 => {
1852            cfg_if! {
1853                if #[cfg(any(feature = "f3", feature = "g0"))] {
1854                    let ccr = &regs.ch5.cr;
1855                } else {
1856                    let ccr = &regs.ccr5;
1857                }
1858            }
1859            disable_interrupt!(ccr, interrupt);
1860        }
1861        #[cfg(not(feature = "g0"))]
1862        DmaChannel::C6 => {
1863            cfg_if! {
1864                if #[cfg(any(feature = "f3", feature = "g0"))] {
1865                    let ccr = &regs.ch6.cr;
1866                } else {
1867                    let ccr = &regs.ccr6;
1868                }
1869            }
1870            disable_interrupt!(ccr, interrupt);
1871        }
1872        #[cfg(not(feature = "g0"))]
1873        DmaChannel::C7 => {
1874            cfg_if! {
1875                if #[cfg(any(feature = "f3", feature = "g0"))] {
1876                    let ccr = &regs.ch7.cr;
1877                } else {
1878                    let ccr = &regs.ccr7;
1879                }
1880            }
1881            disable_interrupt!(ccr, interrupt);
1882        }
1883        #[cfg(any(feature = "l5", feature = "g4"))]
1884        DmaChannel::C8 => {
1885            let ccr = &regs.ccr8;
1886            disable_interrupt!(ccr, interrupt);
1887        }
1888    };
1889}
1890
1891#[cfg(feature = "h7")]
1892fn enable_interrupt_internal<D>(regs: &mut D, channel: DmaChannel, interrupt: DmaInterrupt)
1893where
1894    D: Deref<Target = dma1::RegisterBlock>,
1895{
1896    // Can only be set when the channel is disabled.
1897    let cr = &regs.st[channel as usize].cr;
1898
1899    match interrupt {
1900        DmaInterrupt::TransferError => cr.modify(|_, w| w.teie().set_bit()),
1901        DmaInterrupt::HalfTransfer => cr.modify(|_, w| w.htie().set_bit()),
1902        DmaInterrupt::TransferComplete => cr.modify(|_, w| w.tcie().set_bit()),
1903        DmaInterrupt::DirectModeError => cr.modify(|_, w| w.dmeie().set_bit()),
1904        DmaInterrupt::FifoError => regs.st[channel as usize]
1905            .fcr
1906            .modify(|_, w| w.feie().set_bit()),
1907    }
1908}
1909
1910#[cfg(feature = "h7")]
1911fn disable_interrupt_internal<D>(regs: &mut D, channel: DmaChannel, interrupt: DmaInterrupt)
1912where
1913    D: Deref<Target = dma1::RegisterBlock>,
1914{
1915    // Can only be set when the channel is disabled.
1916    let cr = &regs.st[channel as usize].cr;
1917
1918    // todo DRY
1919
1920    match interrupt {
1921        DmaInterrupt::TransferError => cr.modify(|_, w| w.teie().clear_bit()),
1922        DmaInterrupt::HalfTransfer => cr.modify(|_, w| w.htie().clear_bit()),
1923        DmaInterrupt::TransferComplete => cr.modify(|_, w| w.tcie().clear_bit()),
1924        DmaInterrupt::DirectModeError => cr.modify(|_, w| w.dmeie().clear_bit()),
1925        DmaInterrupt::FifoError => regs.st[channel as usize]
1926            .fcr
1927            .modify(|_, w| w.feie().clear_bit()),
1928    }
1929}
1930
1931/// Enable a specific type of interrupt.
1932pub fn enable_interrupt(periph: DmaPeriph, channel: DmaChannel, interrupt: DmaInterrupt) {
1933    match periph {
1934        DmaPeriph::Dma1 => {
1935            let mut regs = unsafe { &(*DMA1::ptr()) };
1936            enable_interrupt_internal(&mut regs, channel, interrupt);
1937        }
1938        #[cfg(not(any(feature = "f3x4", feature = "g0", feature = "wb")))]
1939        DmaPeriph::Dma2 => {
1940            let mut regs = unsafe { &(*pac::DMA2::ptr()) };
1941            enable_interrupt_internal(&mut regs, channel, interrupt);
1942        }
1943    }
1944}
1945
1946/// Disable a specific type of interrupt.
1947pub fn disable_interrupt(periph: DmaPeriph, channel: DmaChannel, interrupt: DmaInterrupt) {
1948    match periph {
1949        DmaPeriph::Dma1 => {
1950            let mut regs = unsafe { &(*DMA1::ptr()) };
1951            disable_interrupt_internal(&mut regs, channel, interrupt);
1952        }
1953        #[cfg(not(any(feature = "f3x4", feature = "g0", feature = "wb")))]
1954        DmaPeriph::Dma2 => {
1955            let mut regs = unsafe { &(*pac::DMA2::ptr()) };
1956            disable_interrupt_internal(&mut regs, channel, interrupt);
1957        }
1958    }
1959}
1960
1961/// Clear an interrupt flag.
1962pub fn clear_interrupt(periph: DmaPeriph, channel: DmaChannel, interrupt: DmaInterrupt) {
1963    match periph {
1964        DmaPeriph::Dma1 => {
1965            let mut regs = unsafe { &(*DMA1::ptr()) };
1966            clear_interrupt_internal(&mut regs, channel, interrupt);
1967        }
1968        #[cfg(not(any(feature = "f3x4", feature = "g0", feature = "wb")))]
1969        DmaPeriph::Dma2 => {
1970            let mut regs = unsafe { &(*pac::DMA2::ptr()) };
1971            clear_interrupt_internal(&mut regs, channel, interrupt);
1972        }
1973    }
1974}
1975
1976#[cfg(any(
1977    feature = "l5",
1978    feature = "g0",
1979    feature = "g4",
1980    feature = "h7",
1981    feature = "wb",
1982    feature = "wl",
1983))]
1984/// Configure a specific DMA channel to work with a specific peripheral.
1985pub fn mux(periph: DmaPeriph, channel: DmaChannel, input: DmaInput) {
1986    // Note: This is similar in API and purpose to `channel_select` above,
1987    // for different families. We're keeping it as a separate function instead
1988    // of feature-gating within the same function so the name can be recognizable
1989    // from the RM etc.
1990
1991    // G4 example:
1992    // "The mapping of resources to DMAMUX is hardwired.
1993    // DMAMUX is used with DMA1 and DMA2:
1994    // For category 3 and category 4 devices:
1995    // •
1996    // DMAMUX channels 0 to 7 are connected to DMA1 channels 1 to 8
1997    // •
1998    // DMAMUX channels 8 to 15 are connected to DMA2 channels 1 to 8
1999    // For category 2 devices:
2000    // •
2001    // DMAMUX channels 0 to 5 are connected to DMA1 channels 1 to 6
2002    // •
2003    // DMAMUX channels 6 to 11 are connected to DMA2 channels 1 to 6"
2004    //
2005    // H723/25/33/35"
2006    // DMAMUX1 is used with DMA1 and DMA2 in D2 domain
2007    // •
2008    // DMAMUX1 channels 0 to 7 are connected to DMA1 channels 0 to 7
2009    // •
2010    // DMAMUX1 channels 8 to 15 are connected to DMA2 channels 0 to 7
2011    // (Note: The H7 and G4 cat 3/4 mappings are the same, except for H7's use of 0-7, and G4's use of 1-8.)
2012
2013    // todo: With this in mind, some of the mappings below are not correct on some G4 variants.
2014
2015    unsafe {
2016        let mux = unsafe { &(*DMAMUX::ptr()) };
2017
2018        #[cfg(feature = "g4")]
2019        let rcc = unsafe { &(*RCC::ptr()) };
2020        #[cfg(feature = "g4")]
2021        rcc.ahb1enr.modify(|_, w| w.dmamuxen().set_bit());
2022
2023        match periph {
2024            DmaPeriph::Dma1 => {
2025                #[cfg(not(feature = "h7"))]
2026                match channel {
2027                    // Note the offset by 1, due to mismatch in DMA channels starting at 1, and DMAMUX
2028                    // channels starting at 0. Ops tested this is correct on G4.
2029                    DmaChannel::C1 => mux.c0cr.modify(|_, w| w.dmareq_id().bits(input as u8)),
2030                    DmaChannel::C2 => mux.c1cr.modify(|_, w| w.dmareq_id().bits(input as u8)),
2031                    DmaChannel::C3 => mux.c2cr.modify(|_, w| w.dmareq_id().bits(input as u8)),
2032                    DmaChannel::C4 => mux.c3cr.modify(|_, w| w.dmareq_id().bits(input as u8)),
2033                    DmaChannel::C5 => mux.c4cr.modify(|_, w| w.dmareq_id().bits(input as u8)),
2034                    #[cfg(not(feature = "g0"))]
2035                    DmaChannel::C6 => mux.c5cr.modify(|_, w| w.dmareq_id().bits(input as u8)),
2036                    #[cfg(not(feature = "g0"))]
2037                    DmaChannel::C7 => mux.c6cr.modify(|_, w| w.dmareq_id().bits(input as u8)),
2038                    #[cfg(any(feature = "l5", feature = "g4"))]
2039                    DmaChannel::C8 => mux.c7cr.modify(|_, w| w.dmareq_id().bits(input as u8)),
2040                }
2041
2042                #[cfg(feature = "h7")]
2043                mux.ccr[channel as usize].modify(|_, w| w.dmareq_id().bits(input as u8));
2044            }
2045            #[cfg(not(any(
2046                all(feature = "g0", not(any(feature = "g0b1", feature = "g0c1"))),
2047                feature = "wb"
2048            )))]
2049            DmaPeriph::Dma2 => {
2050                #[cfg(not(feature = "h7"))]
2051                match channel {
2052                    DmaChannel::C1 => mux.c8cr.modify(|_, w| w.dmareq_id().bits(input as u8)),
2053                    DmaChannel::C2 => mux.c9cr.modify(|_, w| w.dmareq_id().bits(input as u8)),
2054                    DmaChannel::C3 => mux.c10cr.modify(|_, w| w.dmareq_id().bits(input as u8)),
2055                    DmaChannel::C4 => mux.c11cr.modify(|_, w| w.dmareq_id().bits(input as u8)),
2056                    DmaChannel::C5 => mux.c12cr.modify(|_, w| w.dmareq_id().bits(input as u8)),
2057                    #[cfg(not(feature = "g0"))]
2058                    DmaChannel::C6 => mux.c13cr.modify(|_, w| w.dmareq_id().bits(input as u8)),
2059                    #[cfg(not(any(feature = "g0", feature = "wb", feature = "wl")))]
2060                    DmaChannel::C7 => mux.c14cr.modify(|_, w| w.dmareq_id().bits(input as u8)),
2061                    #[cfg(any(feature = "wb", feature = "wl"))]
2062                    DmaChannel::C7 => (), // Maybe no channel 7 on DMA2 on these platforms.
2063                    #[cfg(any(feature = "l5", feature = "g4"))]
2064                    DmaChannel::C8 => mux.c15cr.modify(|_, w| w.dmareq_id().bits(input as u8)),
2065                }
2066
2067                #[cfg(feature = "h7")]
2068                mux.ccr[channel as usize + 8].modify(|_, w| w.dmareq_id().bits(input as u8));
2069            }
2070        }
2071    }
2072}
2073
2074#[cfg(feature = "h7")]
2075/// Configure a specific DMA channel to work with a specific peripheral, on DMAMUX2.
2076pub fn mux2(periph: DmaPeriph, channel: DmaChannel, input: DmaInput2, mux: &mut DMAMUX2) {
2077    mux.ccr[channel as usize].modify(|_, w| unsafe { w.dmareq_id().bits(input as u8) });
2078}
2079
2080// todo: Enable this for other MCUs as requried
2081/// Enable the DMA mux RCC clock. Applicable to some variants, but no others. (H7 and G0 don't use it,
2082/// for example)
2083#[cfg(any(feature = "g4", feature = "wb"))]
2084pub fn enable_mux1() {
2085    let rcc = unsafe { &(*RCC::ptr()) };
2086
2087    cfg_if! {
2088        if #[cfg(feature = "g4")] {
2089            // Note inconsistency between `dmamux` and `dmamux`; can't use macro here.
2090            rcc.ahb1enr.modify(|_, w| w.dmamuxen().set_bit());
2091            rcc.ahb1rstr.modify(|_, w| w.dmamux1rst().set_bit());
2092            rcc.ahb1rstr.modify(|_, w| w.dmamux1rst().clear_bit());
2093        } else {
2094            rcc_en_reset!(ahb1, dmamux, rcc);
2095        }
2096    }
2097}
2098
2099#[cfg(feature = "l4")] // Only required on L4
2100/// Select which peripheral on a given channel we're using.
2101/// See L44 RM, Table 41.
2102pub(crate) fn channel_select<D>(regs: &mut D, input: DmaInput)
2103where
2104    D: Deref<Target = dma1::RegisterBlock>,
2105{
2106    // todo: Allow selecting channels in pairs to save a write.
2107    let val = input.dma1_channel_select();
2108    regs.cselr.modify(|_, w| match input.dma1_channel() {
2109        DmaChannel::C1 => w.c1s().bits(val),
2110        DmaChannel::C2 => w.c2s().bits(val),
2111        DmaChannel::C3 => w.c3s().bits(val),
2112        DmaChannel::C4 => w.c4s().bits(val),
2113        DmaChannel::C5 => w.c5s().bits(val),
2114        DmaChannel::C6 => w.c6s().bits(val),
2115        DmaChannel::C7 => w.c7s().bits(val),
2116    });
2117}
2118
2119// todo: Code below is for experimental struct-per-channel API
2120macro_rules! make_chan_struct {
2121    // ($Periph:ident, $PERIPH:ident, $periph:ident, $ch:expr) => {
2122    ($periph: expr, $ch:expr) => {
2123        paste! {
2124            /// Experimental/WIP channel-based DMA struct.
2125            pub struct [<Dma $periph Ch $ch>] {
2126                // #[cfg(feature = "h7")]
2127                // regs: dma1::st // todo?
2128            }
2129
2130            impl [<Dma $periph Ch $ch>] {
2131                /// Initialize a DMA peripheral, including enabling and resetting
2132                /// its RCC peripheral clock.
2133                /// Note that the clock may have already been enabled by a different channel's
2134                /// constructor.
2135                pub fn new() -> Self {
2136                    // todo: Enable RCC for DMA 2 etc!
2137                    let rcc = unsafe { &(*RCC::ptr()) };
2138                    cfg_if! {
2139                        if #[cfg(feature = "f3")] {
2140                            rcc.ahbenr.modify(|_, w| w.dma1en().set_bit()); // no dmarst on F3.
2141                        } else if #[cfg(feature = "g0")] {
2142                            rcc_en_reset!(ahb1, dma, rcc);
2143                        } else {
2144                            rcc_en_reset!(ahb1, [<dma $periph>], rcc);
2145                        }
2146                    }
2147
2148                    Self { }
2149                }
2150
2151                fn regs(&self) -> &[<dma $periph>]::RegisterBlock {
2152                    unsafe { &(*[<DMA $periph>]::ptr())}
2153                }
2154
2155                #[cfg(feature = "h7")]
2156                fn ccr(&self) -> &[<dma $periph>]::st::CR {
2157                // fn ccr(&self) -> &u8 {
2158                    &self.regs().st[$ch].cr
2159                }
2160
2161                #[cfg(not(any(feature = "h7", feature = "f3", feature = "g0")))]
2162                fn ccr(&self) -> &[<dma $periph>]::[<CCR $ch>] {
2163                    &self.regs().[<ccr $ch>]
2164                }
2165
2166                #[cfg(any(feature = "f3", feature = "g0"))]
2167                // fn ccr(&self) -> &[<dma $periph>]::ch::cr {
2168                 fn ccr(&self) -> i8 {
2169                    &self.regs().[<ch $ch>].cr
2170                }
2171
2172                #[cfg(not(feature = "h7"))] // due to num_data size diff
2173                /// Configure a DMA channel. See L4 RM 0394, section 11.4.4. Sets the Transfer Complete
2174                /// interrupt. Note that this fn has been (perhaps) depreciated by the standalone fn.
2175                pub fn cfg_channel(
2176                    &mut self,
2177                    periph_addr: u32,
2178                    mem_addr: u32,
2179                    num_data: u16,
2180                    direction: Direction,
2181                    periph_size: DataSize,
2182                    mem_size: DataSize,
2183                    cfg: ChannelCfg,
2184                ) {
2185                    cfg_channel(
2186                        &mut self.regs(),
2187                        DmaChannel::[<C $ch>],
2188                        periph_addr,
2189                        mem_addr,
2190                        num_data,
2191                        direction,
2192                        periph_size,
2193                        mem_size,
2194                        cfg,
2195                    )
2196                }
2197
2198                #[cfg(feature = "h7")]
2199                /// Configure a DMA channel. See L4 RM 0394, section 11.4.4. Sets the Transfer Complete
2200                /// interrupt. Note that this fn has been (perhaps) depreciated by the standalone fn.
2201                pub fn cfg_channel(
2202                    &mut self,
2203                    periph_addr: u32,
2204                    mem_addr: u32,
2205                    num_data: u32,
2206                    direction: Direction,
2207                    periph_size: DataSize,
2208                    mem_size: DataSize,
2209                    cfg: ChannelCfg,
2210                ) {
2211                    cfg_channel(
2212                        &mut self.regs(),
2213                        DmaChannel::[<C $ch>],
2214                        periph_addr,
2215                        mem_addr,
2216                        num_data,
2217                        direction,
2218                        periph_size,
2219                        mem_size,
2220                        cfg,
2221                    )
2222                }
2223
2224                /// Stop a DMA transfer, if in progress.
2225                pub fn stop(&mut self) {
2226                    let ccr = self.ccr();
2227
2228                    ccr.modify(|_, w| w.en().clear_bit());
2229                    while ccr.read().en().bit_is_set() {}
2230                }
2231
2232                /// Enable a specific type of interrupt.
2233                pub fn enable_interrupt(&mut self, interrupt: DmaInterrupt) {
2234                    enable_interrupt_internal(&mut self.regs(), DmaChannel::[<C $ch>], interrupt);
2235                }
2236
2237                /// Clear an interrupt flag.
2238                pub fn clear_interrupt(&mut self, interrupt: DmaInterrupt) {
2239                    clear_interrupt_internal(&mut self.regs(), DmaChannel::[<C $ch>], interrupt);
2240                }
2241                // todo: Other methods.
2242            }
2243        }
2244    };
2245}
2246
2247// todo: As above, you may need more feature-gating, esp on
2248// todo DMA2.
2249// Note: G0 is limited, eg for some variants only up to DMA1, ch5.
2250cfg_if! {
2251    if #[cfg(not(any(feature = "f3", feature = "g0")))] {
2252        #[cfg(feature = "h7")]
2253        make_chan_struct!(1, 0);
2254        make_chan_struct!(1, 1);
2255        make_chan_struct!(1, 2);
2256        make_chan_struct!(1, 3);
2257        make_chan_struct!(1, 4);
2258        make_chan_struct!(1, 5);
2259        #[cfg(not(feature = "g0"))]
2260        make_chan_struct!(1, 6);
2261        #[cfg(not(feature = "g0"))]
2262        make_chan_struct!(1, 7);
2263        #[cfg(any(feature = "l5", feature = "g4"))]
2264        make_chan_struct!(1, 8);
2265
2266        #[cfg(feature = "h7")]
2267        make_chan_struct!(2, 0);
2268        #[cfg(not(any(feature = "g0", feature = "wb")))]
2269        make_chan_struct!(2, 1);
2270        #[cfg(not(any(feature = "g0", feature = "wb")))]
2271        make_chan_struct!(2, 2);
2272        #[cfg(not(any(feature = "g0", feature = "wb")))]
2273        make_chan_struct!(2, 3);
2274        #[cfg(not(any(feature = "g0", feature = "wb")))]
2275        make_chan_struct!(2, 4);
2276        #[cfg(not(any(feature = "g0", feature = "wb")))]
2277        make_chan_struct!(2, 5);
2278        #[cfg(not(any(feature = "g0", feature = "wb")))]
2279        make_chan_struct!(2, 6);
2280        #[cfg(not(any(feature = "g0", feature = "wb")))]
2281        make_chan_struct!(2, 7);
2282        #[cfg(any(feature = "l5", feature = "g4"))]
2283        make_chan_struct!(2, 8);
2284    }
2285}