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