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
4use core::{
5    ops::Deref,
6    sync::atomic::{self, Ordering},
7};
8
9use cfg_if::cfg_if;
10
11use crate::{
12    error::{Error, Result},
13    pac::RCC,
14    util::bounded_loop,
15};
16
17cfg_if! {
18    if #[cfg(any(
19        feature = "f3x4",
20        feature = "f301",
21        all(feature = "g0", not(any(feature = "g0b0", feature = "g0b1", feature = "g0c1")))
22    ))] {
23        use crate::{pac::{dma1, DMA1}, util::rcc_en_reset};
24    } else if #[cfg(feature = "c0")] { // pac bug?
25        use crate::{pac::{dma as dma1, DMA as DMA1}, util::rcc_en_reset};
26    } else {
27        use crate::{pac::{dma1, dma2, DMA1, DMA2}, util::rcc_en_reset};
28    }
29}
30// #[cfg(any(feature = "g0", feature = "wb", feature = "f3"))]
31// F4 family does not have a multipexer infront of the DMA.
32#[cfg(any(feature = "g0", feature = "g4", feature = "wl"))]
33use crate::pac::DMAMUX;
34// todo: DMAMUX2 support (Not sure if WB has it, but H7 has both).
35#[cfg(any(feature = "l5", feature = "wb", feature = "h7"))]
36use crate::pac::DMAMUX1 as DMAMUX;
37#[cfg(feature = "h7")]
38use crate::pac::DMAMUX2;
39
40// todo: Several sections of this are only correct for DMA1.
41
42/// Errors that can occur when performing DMA.
43#[non_exhaustive]
44#[cfg_attr(feature = "defmt", derive(defmt::Format))]
45#[derive(Debug, Clone, Copy, Eq, PartialEq)]
46pub enum DmaError {
47    TransferError,
48    #[cfg(any(feature = "h7", feature = "f4"))]
49    FifoError,
50    #[cfg(any(feature = "h7", feature = "f4"))]
51    DirectModeError,
52}
53
54#[derive(Clone, Copy)]
55pub enum DmaPeriph {
56    Dma1,
57    #[cfg(dma2)]
58    Dma2,
59}
60
61#[derive(Copy, Clone)]
62#[repr(usize)]
63#[cfg(not(any(feature = "h7", feature = "wl", feature = "wb", feature = "g0")))]
64/// A list of DMA input sources. The integer values represent their DMAMUX register value, on
65/// MCUs that use this. G4 RM, Table 91: DMAMUX: Assignment of multiplexer inputs to resources.
66pub enum DmaInput {
67    // This (on G4) goes up to 115. For now, just implement things we're likely
68    // to use in this HAL. Make sure this is compatible beyond G4.
69    Adc1 = 5,
70    Dac1Ch1 = 6,
71    Dac1Ch2 = 7,
72    Tim6Up = 8,
73    Tim7Up = 9,
74    Spi1Rx = 10,
75    Spi1Tx = 11,
76    Spi2Rx = 12,
77    Spi2Tx = 13,
78    Spi3Rx = 14,
79    Spi3Tx = 15,
80    I2c1Rx = 16,
81    I2c1Tx = 17,
82    I2c2Rx = 18,
83    I2c2Tx = 19,
84    I2c3Rx = 20,
85    I2c3Tx = 21,
86    I2c4Rx = 22,
87    I2c4Tx = 23,
88    Usart1Rx = 24,
89    Usart1Tx = 25,
90    Usart2Rx = 26,
91    Usart2Tx = 27,
92    Usart3Rx = 28,
93    Usart3Tx = 29,
94    Uart4Rx = 30,
95    Uart4Tx = 31,
96    Uart5Rx = 32,
97    Uart5Tx = 33,
98    Lpuart1Rx = 34,
99    Lpuart1Tx = 35,
100    Adc2 = 36,
101    Adc3 = 37,
102    Adc4 = 38,
103    Adc5 = 39,
104    Quadspi = 40,
105    Dac2Ch1 = 41,
106    Tim1Ch1 = 42,
107    Tim1Ch2 = 43,
108    Tim1Ch3 = 44,
109    Tim1Ch4 = 45,
110    TimUp = 46,
111    Tim1Trig = 47,
112    Tim1Com = 48,
113    Tim8Ch1 = 49,
114    Tim8Ch2 = 50,
115    Tim8Ch3 = 51,
116    Tim8Ch4 = 52,
117    Tim8Up = 53,
118    Tim8Trig = 54,
119    Tim8Com = 55,
120    Tim2Ch1 = 56,
121    Tim2Ch2 = 57,
122    Tim2Ch3 = 58,
123    Tim2Ch4 = 59,
124    Tim2Up = 60,
125    Tim3Ch1 = 61,
126    Tim3Ch2 = 62,
127    Tim3Ch3 = 63,
128    Tim3Ch4 = 64,
129    Tim3Up = 65,
130    Tim3Trig = 66,
131    Tim4Ch1 = 67,
132    Tim4Ch2 = 68,
133    Tim4Ch3 = 69,
134    Tim4Ch4 = 70,
135    Tim4Up = 71,
136    Sai1A = 108,
137    Sai1B = 109,
138    // todo: These SAI2 values are bogus; can't find on G4 DMA mux.
139    Sai2A = 203,
140    Sai2B = 204,
141    // todo: Can't find DFSDM periph on G4 rm: These assigned values are bogus.
142    Dfsdm1F0 = 200,
143    Dfsdm1F1 = 201,
144    Dfsdm1F2 = 205,
145    Dfsdm1F3 = 206,
146}
147
148#[derive(Copy, Clone)]
149#[repr(usize)]
150#[cfg(feature = "g0")]
151/// G0x0 RM, 10.3.2: DMAMUX mapping
152/// G0x1 RM, 11.3.2: DMAMUX mapping
153pub enum DmaInput {
154    Adc = 5,
155    AesIn = 6,
156    AesOut = 7,
157    Dac1Ch1 = 8,
158    Dac1Ch2 = 9,
159    I2c1Rx = 10,
160    I2c1Tx = 11,
161    I2c2Rx = 12,
162    I2c2Tx = 13,
163    Lpuart1Rx = 14,
164    Lpuart1Tx = 15,
165    Spi1Rx = 16,
166    Spi1Tx = 17,
167    Spi2Rx = 18,
168    Spi2Tx = 19,
169    Tim1Ch1 = 20,
170    Tim1Ch2 = 21,
171    Tim1Ch3 = 22,
172    Tim1Ch4 = 23,
173    Tim1TrigCom = 24,
174    Tim1Up = 25,
175    Tim2Ch1 = 26,
176    Tim2Ch2 = 27,
177    Tim2Ch3 = 28,
178    Tim2Ch4 = 29,
179    Tim2Trig = 30,
180    Tim2Up = 31,
181    Tim3Ch1 = 32,
182    Tim3Ch2 = 33,
183    Tim3Ch3 = 34,
184    Tim3Ch4 = 35,
185    Tim3Trig = 36,
186    Tim3Up = 37,
187    Tim6Up = 38,
188    Tim7Up = 39,
189    Tim15Ch1 = 40,
190    Tim15Ch2 = 41,
191    Tim15TrigCom = 42,
192    Tim15Up = 43,
193    Tim16Ch1 = 44,
194    Tim16Com = 45,
195    Tim16Up = 46,
196    Tim17Ch1 = 47,
197    Tim17Com = 48,
198    Tim17Up = 49,
199    Usart1Rx = 50,
200    Usart1Tx = 51,
201    Usart2Rx = 52,
202    Usart2Tx = 53,
203    Usart3Rx = 54,
204    Usart3Tx = 55,
205    Usart4Rx = 56,
206    Usart4Tx = 57,
207    Ucpd1Rx = 58,
208    Ucpd1Tx = 59,
209    Ucpd2Rx = 60,
210    Ucpd2Tx = 61,
211    I2c3Rx = 62,
212    I2c3Tx = 63,
213    Lpuart2Rx = 64,
214    Lpuart2Tx = 65,
215    Spi3Rx = 66,
216    Spi3Tx = 67,
217    Tim4Ch1 = 68,
218    Tim4Ch2 = 69,
219    Tim4Ch3 = 70,
220    Tim4Ch4 = 71,
221    Tim4Trig = 72,
222    Tim4Up = 73,
223    Usart5Rx = 74,
224    Usart5Tx = 75,
225    Usart6Rx = 76,
226    Usart6Tx = 77,
227}
228
229#[derive(Copy, Clone)]
230#[repr(usize)]
231#[cfg(feature = "wl")]
232/// WL RM, 14.3.2: DMAMUX1 mapping
233pub enum DmaInput {
234    Adc = 5,
235    DacOut1 = 6,
236    // Dac1Ch2 = 7,
237    Spi1Rx = 7,
238    Spi1Tx = 8,
239    Spi2Rx = 9,
240    Spi2Tx = 10,
241    I2c1Rx = 11,
242    I2c1Tx = 12,
243    I2c2Rx = 13,
244    I2c2Tx = 14,
245    I2c3Rx = 15,
246    I2c3Tx = 16,
247    Usart1Rx = 17,
248    Usart1Tx = 18,
249    Usart2Rx = 19,
250    Usart2Tx = 20,
251    Lpuart1Rx = 21,
252    Lpuart1Tx = 22,
253    Tim1Ch1 = 23,
254    Tim1Ch2 = 24,
255    Tim1Ch3 = 25,
256    Tim1Ch4 = 26,
257    TimUp = 27,
258    Tim1Trig = 28,
259    Tim1Com = 29,
260    Tim2Ch1 = 30,
261    Tim2Ch2 = 31,
262    Tim2Ch3 = 32,
263    Tim2Ch4 = 33,
264    Tim2Up = 34,
265    Tim16Ch1 = 35,
266    Tim16Up = 36,
267    Tim17Ch1 = 37,
268    Tim17Up = 38,
269    AesIn = 39,
270    AesOut = 40,
271    SubghzSpiRx = 41,
272    SubghzSpiTx = 42,
273}
274
275#[derive(Copy, Clone)]
276#[repr(usize)]
277#[cfg(feature = "wb")]
278/// WB RM, 12.3.2: DMAMUX mapping
279pub enum DmaInput {
280    Adc1 = 5,
281    Spi1Rx = 6,
282    Spi1Tx = 7,
283    Spi2Rx = 8,
284    Spi2Tx = 9,
285    I2c1Rx = 10,
286    I2c1Tx = 11,
287    I2c3Rx = 12,
288    I2c3Tx = 13,
289    Usart1Rx = 14,
290    Usart1Tx = 15,
291    Lpuart1Rx = 16,
292    Lpuart1Tx = 17,
293    Sai1A = 18,
294    Sai1B = 19,
295    Quadspi = 20,
296    Tim1Ch1 = 21,
297    Tim1Ch2 = 22,
298    Tim1Ch3 = 23,
299    Tim1Ch4 = 24,
300    TimUp = 25,
301    Tim1Trig = 26,
302    Tim1Com = 27,
303    Tim2Ch1 = 28,
304    Tim2Ch2 = 29,
305    Tim2Ch3 = 30,
306    Tim2Ch4 = 31,
307    Tim2Up = 32,
308    Tim16Ch1 = 33,
309    Tim16Up = 34,
310    Tim17Ch1 = 35,
311    Tim17Up = 36,
312    Aes1In = 37,
313    Aes1Out = 38,
314    Aes2In = 39,
315    Aes2Out = 40,
316}
317
318// todo: Trigger, synchronization etc mappings. Perhaps DmaTrigger, DmaSync enums etc.
319
320#[derive(Copy, Clone)]
321#[repr(usize)]
322#[cfg(feature = "h7")]
323/// A list of DMA input sources. The integer values represent their DMAMUX register value, on
324/// MCUs that use this. H743 RM, Table 121: DMAMUX1: Assignment of multiplexer inputs to resources.
325/// (Table 118 in RM0468)
326/// Note that this is only for DMAMUX1
327pub enum DmaInput {
328    Adc1 = 9,
329    Adc2 = 10,
330    Tim1Ch1 = 11,
331    Tim1Ch2 = 12,
332    Tim1Ch3 = 13,
333    Tim1Ch4 = 14,
334    Tim1Up = 15,
335    Tim1Trig = 16,
336    Tim1Com = 17,
337    Tim2Ch1 = 18,
338    Tim2Ch2 = 19,
339    Tim2Ch3 = 20,
340    Tim2Ch4 = 21,
341    Tim2Up = 22,
342    Tim3Ch1 = 23,
343    Tim3Ch2 = 24,
344    Tim3Ch3 = 25,
345    Tim3Ch4 = 26,
346    Tim3Up = 27,
347    Tim3Trig = 28,
348    Tim4Ch1 = 29,
349    Tim4Ch2 = 30,
350    Tim4Ch3 = 31,
351    Tim4Up = 32,
352    I2c1Rx = 33,
353    I2c1Tx = 34,
354    I2c2Rx = 35,
355    I2c2Tx = 36,
356    Spi1Rx = 37,
357    Spi1Tx = 38,
358    Spi2Rx = 39,
359    Spi2Tx = 40,
360    Usart1Rx = 41,
361    Usart1Tx = 42,
362    Usart2Rx = 43,
363    Usart2Tx = 44,
364    Usart3Rx = 45,
365    Usart3Tx = 46,
366    Tim8Ch1 = 47,
367    Tim8Ch2 = 48,
368    Tim8Ch3 = 49,
369    Tim8Ch4 = 50,
370    Tim8Up = 51,
371    Tim8Trig = 52,
372    Tim8Com = 53,
373    Tim5Ch1 = 55,
374    Tim5Ch2 = 56,
375    Tim5Ch3 = 57,
376    Tim5Ch4 = 58,
377    Tim5Up = 59,
378    Tim5Trig = 60,
379    Spi3Rx = 61,
380    Spi3Tx = 62,
381    Uart4Rx = 63,
382    Uart4Tx = 64,
383    Uart5Rx = 65,
384    Uart5Tx = 66,
385    DacCh1 = 67,
386    DacCh2 = 68,
387    Tim6Up = 69,
388    Tim7Up = 70,
389    Uart6Rx = 71,
390    Uart6Tx = 72,
391    I2c3Rx = 73,
392    I2c3Tx = 74,
393    Dcmi = 75,
394    CrypIn = 76,
395    CrypOut = 77,
396    HashIn = 78,
397    Uart7Rx = 79,
398    Uart7Tx = 80,
399    Uart8Rx = 81,
400    Uart8Tx = 82,
401    Sai1A = 87,
402    Sai1B = 88,
403    Sai2A = 89,
404    Sai2B = 90,
405    Dfsdm1F0 = 101,
406    Dfsdm1F1 = 102,
407    Dfsdm1F2 = 103,
408    Dfsdm1F3 = 104,
409    Sai3A = 113,
410    Sai3B = 114,
411    Adc3 = 115,
412    Uart9Rx = 116,
413    Uart9Tx = 117,
414    Uart10Rx = 118,
415    Uart10Tx = 119,
416}
417
418#[derive(Copy, Clone)]
419#[repr(usize)]
420#[cfg(feature = "h7")]
421/// A list of DMA input sources for DMAMUX2. Used for BDMA. See H742 RM, Table 124.
422pub enum DmaInput2 {
423    Lpuart1Rx = 9,
424    Lpuart1Tx = 10,
425    Spi6Rx = 11,
426    Spi6Tx = 12,
427    I2c4Rx = 13,
428    I3crTx = 14,
429    Sai4A = 15,
430    Sai4B = 16,
431}
432
433impl DmaInput {
434    #[cfg(any(feature = "f3", feature = "l4"))]
435    /// Select the hard set channel associated with a given input source. See L44 RM, Table 41.
436    pub fn dma1_channel(&self) -> DmaChannel {
437        match self {
438            Self::Adc1 => DmaChannel::C1,
439            Self::Dac1Ch1 => DmaChannel::C3,
440            Self::Dac1Ch2 => DmaChannel::C4,
441            // Self::Tim6Up => 8,
442            // Self::Tim7Up => 9,
443            Self::Spi1Rx => DmaChannel::C2,
444            Self::Spi1Tx => DmaChannel::C3,
445            Self::Spi2Rx => DmaChannel::C4,
446            Self::Spi2Tx => DmaChannel::C5,
447            // Self::Spi3Rx => 14,
448            // Self::Spi3Tx => 15,
449            Self::I2c1Rx => DmaChannel::C7,
450            Self::I2c1Tx => DmaChannel::C6,
451            Self::I2c2Rx => DmaChannel::C5,
452            Self::I2c2Tx => DmaChannel::C4,
453            Self::I2c3Rx => DmaChannel::C3,
454            // Self::I2c3Tx => 21,
455            // Self::I2c4Rx => 22,
456            // Self::I2c4Tx => 23,
457            Self::Usart1Rx => DmaChannel::C5,
458            Self::Usart1Tx => DmaChannel::C4,
459            Self::Usart2Rx => DmaChannel::C6,
460            Self::Usart2Tx => DmaChannel::C7,
461            Self::Usart3Rx => DmaChannel::C3,
462            Self::Usart3Tx => DmaChannel::C2,
463            // Self::Uart4Rx => 30,
464            // Self::Uart4Tx => 31,
465            // Self::Uart5Rx => 32,
466            // Self::Uart5Tx => 33,
467            // Self::Lpuart1Rx => 34,
468            // Self::Lpuart1Tx => 35,
469            Self::Adc2 => DmaChannel::C2,
470            // Self::Adc3 => 37,
471            // Self::Adc4 => 38,
472            // Self::Adc5 => 39,
473            // Note: Sai1 appears to be DMA2 only.
474            Self::Sai2A => DmaChannel::C6,
475            Self::Sai2B => DmaChannel::C7,
476            Self::Dfsdm1F0 => DmaChannel::C4,
477            Self::Dfsdm1F1 => DmaChannel::C5,
478            Self::Dfsdm1F2 => DmaChannel::C6,
479            Self::Dfsdm1F3 => DmaChannel::C7,
480            _ => unimplemented!(),
481        }
482    }
483
484    #[cfg(feature = "l4")]
485    /// Find the value to set in the DMA_CSELR register, for L4. Ie, channel select value for a given DMA input.
486    /// See L44 RM, Table 41.
487    pub fn dma1_channel_select(&self) -> u8 {
488        match self {
489            Self::Adc1 => 0b000,
490            Self::Dac1Ch1 => 0b0110,
491            Self::Dac1Ch2 => 0b0101,
492            // Self::Tim6Up => 8,
493            // Self::Tim7Up => 9,
494            Self::Spi1Rx => 0b001,
495            Self::Spi1Tx => 0b001,
496            Self::Spi2Rx => 0b001,
497            Self::Spi2Tx => 0b001,
498            // Self::Spi3Rx => 14,
499            // Self::Spi3Tx => 15,
500            Self::I2c1Rx => 0b011,
501            Self::I2c1Tx => 0b011,
502            Self::I2c2Rx => 0b011,
503            Self::I2c2Tx => 0b011,
504            Self::I2c3Rx => 0b011,
505            // Self::I2c3Tx => 21,
506            // Self::I2c4Rx => 22,
507            // Self::I2c4Tx => 23,
508            Self::Usart1Rx => 0b010,
509            Self::Usart1Tx => 0b010,
510            Self::Usart2Rx => 0b010,
511            Self::Usart2Tx => 0b010,
512            Self::Usart3Rx => 0b010,
513            Self::Usart3Tx => 0b010,
514            // Self::Uart4Rx => 30,
515            // Self::Uart4Tx => 31,
516            // Self::Uart5Rx => 32,
517            // Self::Uart5Tx => 33,
518            // Self::Lpuart1Rx => 34,
519            // Self::Lpuart1Tx => 35,
520            Self::Adc2 => 0b000,
521            // Self::Adc3 => 37,
522            // Self::Adc4 => 38,
523            // Self::Adc5 => 39,
524            Self::Dfsdm1F0 => 0b0000,
525            Self::Dfsdm1F1 => 0b0000,
526            Self::Dfsdm1F2 => 0b0000, // todo: QC?
527            Self::Dfsdm1F3 => 0b0000,
528            _ => unimplemented!(),
529        }
530    }
531}
532
533#[derive(Copy, Clone)]
534#[repr(u8)]
535/// L4 RM, 11.4.3, "DMA arbitration":
536/// The priorities are managed in two stages:
537/// • software: priority of each channel is configured in the DMA_CCRx register, to one of
538/// the four different levels:
539/// – very high
540/// – high
541/// – medium
542/// – low
543/// • hardware: if two requests have the same software priority level, the channel with the
544/// lowest index gets priority. For example, channel 2 gets priority over channel 4.
545/// Only write to this when the channel is disabled.
546pub enum Priority {
547    Low = 0b00,
548    Medium = 0b01,
549    High = 0b10,
550    VeryHigh = 0b11,
551}
552
553// Note: L5 also uses the 0 - 7 scheme, but the PAC doesn't reflect this.
554#[derive(Copy, Clone)]
555#[repr(u8)]
556#[cfg(feature = "h7")]
557/// Represents a DMA channel to select, eg when configuring for use with a peripheral.
558/// u8 representation is used to index registers on H7 PAC (And hopefully on future PACs if they
559/// adopt H7's approach)
560pub enum DmaChannel {
561    // H7 calls these Streams. We use the `Channel` name for consistency.
562    #[cfg(feature = "h7")]
563    C0 = 0,
564    C1 = 1,
565    C2 = 2,
566    C3 = 3,
567    #[cfg(not(any(feature = "c011", feature = "c031")))]
568    C4 = 4,
569    #[cfg(not(any(feature = "c011", feature = "c031")))]
570    C5 = 5,
571    // todo: Some G0 variants have channels 6 and 7 and DMA1. (And up to 5 channels on DMA2)
572    //todo: Same for C0: Some variants have these channels.
573    #[cfg(not(any(feature = "g0", feature = "c0")))]
574    C6 = 6,
575    #[cfg(not(any(feature = "g0", feature = "c0")))]
576    C7 = 7,
577}
578
579// todo: Experimenting with offset ch
580#[derive(Copy, Clone)]
581#[repr(u8)]
582#[cfg(not(feature = "h7"))]
583/// Represents a DMA channel to select, eg when configuring for use with a peripheral.
584/// u8 representation is used to index registers on H7 PAC (And hopefully on future PACs if they
585/// adopt H7's approach)
586pub enum DmaChannel {
587    C1 = 0,
588    C2 = 1,
589    C3 = 2,
590    #[cfg(not(any(feature = "c011", feature = "c031")))]
591    C4 = 3,
592    #[cfg(not(any(feature = "c011", feature = "c031")))]
593    C5 = 4,
594    // todo: Some G0 variants have channels 6 and 7 and DMA1. (And up to 5 channels on DMA2)
595    //todo: Same for C0: Some variants have these channels.
596    #[cfg(not(any(feature = "g0", feature = "c0")))]
597    C6 = 5,
598    #[cfg(not(any(feature = "g0", feature = "c0")))]
599    C7 = 6,
600    // todo: Which else have 8? Also, note that some have diff amounts on dma1 vs 2.
601    #[cfg(any(feature = "l5", feature = "g4"))]
602    C8 = 7,
603}
604
605#[derive(Copy, Clone)]
606#[repr(u8)]
607/// Set in ccr().
608/// Can only be set when channel is disabled.
609pub enum Direction {
610    /// DIR = 0 defines typically a peripheral-to-memory transfer
611    ReadFromPeriph = 0,
612    /// DIR = 1 defines typically a memory-to-peripheral transfer.
613    ReadFromMem = 1,
614    MemToMem = 2,
615}
616
617#[derive(Copy, Clone, PartialEq)]
618#[repr(u8)]
619/// Set in ccr().
620/// Can only be set when channel is disabled.
621pub enum Circular {
622    Disabled = 0,
623    Enabled = 1,
624}
625
626#[derive(Copy, Clone)]
627#[repr(u8)]
628/// Peripheral and memory increment mode. (CCR PINC and MINC bits)
629/// Can only be set when channel is disabled.
630pub enum IncrMode {
631    // Can only be set when channel is disabled.
632    Disabled = 0,
633    Enabled = 1,
634}
635
636#[derive(Copy, Clone)]
637#[repr(u8)]
638/// Peripheral and memory increment mode. (CCR PSIZE and MSIZE bits)
639/// Can only be set when channel is disabled.
640pub enum DataSize {
641    S8 = 0b00, // ie 8 bits
642    S16 = 0b01,
643    S32 = 0b10,
644}
645
646#[derive(Copy, Clone)]
647/// Interrupt type. Set in CCR using TEIE, HTIE, and TCIE bits.
648/// Can only be set when channel is disabled.
649pub enum DmaInterrupt {
650    TransferError,
651    HalfTransfer,
652    TransferComplete,
653    #[cfg(feature = "h7")]
654    DirectModeError,
655    #[cfg(feature = "h7")]
656    FifoError,
657}
658
659/// Reduce DRY over channels when configuring a channel's ccr().
660/// We must use a macro here, since match arms balk at the incompatible
661/// types of `CCR1`, `CCR2` etc.
662#[cfg(not(feature = "h7"))]
663macro_rules! set_ccr {
664    ($ccr:expr, $priority:expr, $direction:expr, $circular:expr, $periph_incr:expr, $mem_incr:expr, $periph_size:expr, $mem_size:expr) => {
665        // "The register fields/bits MEM2MEM, PL[1:0], MSIZE[1:0], PSIZE[1:0], MINC, PINC, and DIR
666        // are read-only when EN = 1"
667        let originally_enabled = $ccr().read().en().bit_is_set();
668
669        if originally_enabled {
670            $ccr().modify(|_, w| w.en().clear_bit());
671            bounded_loop!(
672                $ccr().read().en().bit_is_set(),
673                Error::RegisterUnchanged
674            );
675        }
676
677        if let Circular::Enabled = $circular {
678            $ccr().modify(|_, w| w.mem2mem().clear_bit());
679        }
680
681        $ccr().modify(|_, w| unsafe {
682            // – the channel priority
683            w.pl().bits($priority as u8);
684            // – the data transfer direction
685            // This bit [DIR] must be set only in memory-to-peripheral and peripheral-to-memory modes.
686            // 0: read from peripheral
687            w.dir().bit($direction as u8 != 0);
688            // – the circular mode
689            w.circ().bit($circular as u8 != 0);
690            // – the peripheral and memory incremented mode
691            w.pinc().bit($periph_incr as u8 != 0);
692            w.minc().bit($mem_incr as u8 != 0);
693            // – the peripheral and memory data size
694            w.psize().bits($periph_size as u8);
695            w.msize().bits($mem_size as u8);
696            // – the interrupt enable at half and/or full transfer and/or transfer error
697            w.tcie().bit(true);
698            // (See `Step 5` above.)
699            w.en().bit(true)
700        });
701
702        if originally_enabled {
703            $ccr().modify(|_, w| w.en().bit(true));
704            bounded_loop!($ccr().read().en().bit_is_clear(), Error::RegisterUnchanged);
705        }
706    };
707}
708
709/// Reduce DRY over channels when configuring a channel's interrupts.
710#[cfg(not(feature = "h7"))]
711macro_rules! enable_interrupt {
712    ($ccr:expr, $interrupt_type:expr) => {
713        // "It must not be written when the channel is enabled (EN = 1)."
714        let originally_enabled = $ccr().read().en().bit_is_set();
715        if originally_enabled {
716            $ccr().modify(|_, w| w.en().clear_bit());
717            bounded_loop!($ccr().read().en().bit_is_set(), Error::RegisterUnchanged);
718        }
719
720        $ccr().modify(|_, w| match $interrupt_type {
721            DmaInterrupt::TransferError => w.teie().bit(true),
722            DmaInterrupt::HalfTransfer => w.htie().bit(true),
723            DmaInterrupt::TransferComplete => w.tcie().bit(true),
724        });
725
726        if originally_enabled {
727            $ccr().modify(|_, w| w.en().bit(true));
728            bounded_loop!($ccr().read().en().bit_is_clear(), Error::RegisterUnchanged);
729        }
730    };
731}
732
733/// Reduce DRY over channels when configuring a channel's interrupts.
734#[cfg(not(feature = "h7"))]
735macro_rules! disable_interrupt {
736    ($ccr:expr, $interrupt_type:expr) => {
737        // "It must not be written when the channel is disabled (EN = 1)."
738        let originally_disabled = $ccr().read().en().bit_is_set();
739        if originally_disabled {
740            $ccr().modify(|_, w| w.en().clear_bit());
741            bounded_loop!($ccr().read().en().bit_is_set(), Error::RegisterUnchanged);
742        }
743
744        $ccr().modify(|_, w| match $interrupt_type {
745            DmaInterrupt::TransferError => w.teie().clear_bit(),
746            DmaInterrupt::HalfTransfer => w.htie().clear_bit(),
747            DmaInterrupt::TransferComplete => w.tcie().clear_bit(),
748        });
749
750        if originally_disabled {
751            $ccr().modify(|_, w| w.en().bit(true));
752            bounded_loop!($ccr().read().en().bit_is_clear(), Error::RegisterUnchanged);
753        }
754    };
755}
756
757/// This struct is used to pass common (non-peripheral and non-use-specific) data when configuring
758/// a channel.
759#[derive(Clone)]
760pub struct ChannelCfg {
761    /// Channel priority compared to other channels; can be low, medium, high, or very high. Defaults
762    /// to medium.
763    pub priority: Priority,
764    /// Enable or disable circular DMA. If enabled, the transfer continues after reaching the end of
765    /// the buffer, looping to the beginning. A TC interrupt first each time the end is reached, if
766    /// set. Defaults to disabled.
767    pub circular: Circular,
768    /// Whether we increment the peripheral address on data word transfer; generally (and by default)
769    /// disabled.
770    pub periph_incr: IncrMode,
771    /// Whether we increment the buffer address on data word transfer; generally (and by default)
772    /// enabled.
773    pub mem_incr: IncrMode,
774}
775
776impl Default for ChannelCfg {
777    fn default() -> Self {
778        Self {
779            priority: Priority::Medium,
780            circular: Circular::Disabled,
781            // Increment the buffer address, not the peripheral address.
782            periph_incr: IncrMode::Disabled,
783            mem_incr: IncrMode::Enabled,
784        }
785    }
786}
787
788/// Represents a Direct Memory Access (DMA) peripheral.
789pub struct Dma<D> {
790    pub regs: D,
791}
792
793impl<D> Deref for Dma<D>
794where
795    D: Deref<Target = dma1::RegisterBlock>,
796{
797    type Target = dma1::RegisterBlock;
798    fn deref(&self) -> &Self::Target {
799        &self.regs
800    }
801}
802
803impl<D> Dma<D>
804where
805    D: Deref<Target = dma1::RegisterBlock>,
806{
807    /// Initialize a DMA peripheral, including enabling and resetting
808    /// its RCC peripheral clock.
809    pub fn new(regs: D) -> Self {
810        // todo: Enable RCC for DMA 2 etc!
811        let rcc = unsafe { &(*RCC::ptr()) };
812        cfg_if! {
813            if #[cfg(feature = "f3")] {
814                rcc.ahbenr().modify(|_, w| w.dma1en().bit(true)); // no dmarst on F3.
815            } else if #[cfg(any(feature = "g031", feature = "g041", feature = "g051", feature = "g061", feature = "g071", feature = "g081"))] {
816                rcc_en_reset!(ahb1, dma, rcc);
817            } else {
818                rcc_en_reset!(ahb1, dma1, rcc);
819            }
820        }
821
822        Self { regs }
823    }
824
825    // #[cfg(not(feature = "h7"))] // due to num_data size diff
826    // /// Configure a DMA channel. See L4 RM 0394, section 11.4.4. Sets the Transfer Complete
827    // /// interrupt. Note that this fn has been (perhaps) depreciated by the standalone fn.
828    // pub fn cfg_channel(
829    //     &mut self,
830    //     channel: DmaChannel,
831    //     periph_addr: u32,
832    //     mem_addr: u32,
833    //     num_data: u16,
834    //     direction: Direction,
835    //     periph_size: DataSize,
836    //     mem_size: DataSize,
837    //     cfg: ChannelCfg,
838    // ) {
839    //     cfg_channel(
840    //         &mut self.regs,
841    //         channel,
842    //         periph_addr,
843    //         mem_addr,
844    //         num_data,
845    //         direction,
846    //         periph_size,
847    //         mem_size,
848    //         cfg,
849    //     )
850    // }
851
852    // #[cfg(feature = "h7")]
853    /// Configure a DMA channel. See L4 RM 0394, section 11.4.4. Sets the Transfer Complete
854    /// interrupt. Note that this fn has been (perhaps) depreciated by the standalone fn.
855    pub fn cfg_channel(
856        &mut self,
857        channel: DmaChannel,
858        periph_addr: u32,
859        mem_addr: u32,
860        num_data: u32,
861        direction: Direction,
862        periph_size: DataSize,
863        mem_size: DataSize,
864        cfg: ChannelCfg,
865    ) -> Result<()> {
866        cfg_channel(
867            &mut self.regs,
868            channel,
869            periph_addr,
870            mem_addr,
871            num_data,
872            direction,
873            periph_size,
874            mem_size,
875            cfg,
876        )
877    }
878
879    #[cfg(feature = "l4")]
880    pub(crate) fn channel_select(&mut self, input: DmaInput) {
881        channel_select(&mut self.regs, input);
882    }
883
884    /// Stop a DMA transfer, if in progress.
885    pub fn stop(&mut self, channel: DmaChannel) -> Result<()> {
886        stop_internal(&mut self.regs, channel)
887    }
888
889    /// Clear an interrupt flag.
890    pub fn clear_interrupt(&mut self, channel: DmaChannel, interrupt: DmaInterrupt) -> Result<()> {
891        clear_interrupt_internal(&mut self.regs, channel, interrupt)
892    }
893
894    // todo: G0 removed from this fn due to a bug introduced in PAC 0.13
895    #[cfg(not(any(feature = "h7")))]
896    pub fn transfer_is_complete(&mut self, channel: DmaChannel) -> bool {
897        let isr_val = self.regs.isr().read();
898        match channel {
899            DmaChannel::C1 => isr_val.tcif1().bit_is_set(),
900            DmaChannel::C2 => isr_val.tcif2().bit_is_set(),
901            DmaChannel::C3 => isr_val.tcif3().bit_is_set(),
902            #[cfg(not(any(feature = "c011", feature = "c031")))]
903            DmaChannel::C4 => isr_val.tcif4().bit_is_set(),
904            #[cfg(not(any(feature = "c011", feature = "c031")))]
905            DmaChannel::C5 => isr_val.tcif5().bit_is_set(),
906            #[cfg(not(any(feature = "g0", feature = "c0")))]
907            DmaChannel::C6 => isr_val.tcif6().bit_is_set(),
908            #[cfg(not(any(feature = "g0", feature = "c0")))]
909            DmaChannel::C7 => isr_val.tcif7().bit_is_set(),
910            #[cfg(any(feature = "l5", feature = "g4"))]
911            DmaChannel::C8 => isr_val.tcif8().bit_is_set(),
912        }
913    }
914
915    #[cfg(feature = "h7")]
916    pub fn transfer_is_complete(&mut self, channel: DmaChannel) -> bool {
917        match channel {
918            DmaChannel::C0 => self.regs.lisr().read().tcif0().bit_is_set(),
919            DmaChannel::C1 => self.regs.lisr().read().tcif1().bit_is_set(),
920            DmaChannel::C2 => self.regs.lisr().read().tcif2().bit_is_set(),
921            DmaChannel::C3 => self.regs.lisr().read().tcif3().bit_is_set(),
922            DmaChannel::C4 => self.regs.hisr().read().tcif4().bit_is_set(),
923            DmaChannel::C5 => self.regs.hisr().read().tcif5().bit_is_set(),
924            DmaChannel::C6 => self.regs.hisr().read().tcif6().bit_is_set(),
925            DmaChannel::C7 => self.regs.hisr().read().tcif7().bit_is_set(),
926        }
927    }
928
929    /// Enable a specific type of interrupt.
930    pub fn enable_interrupt(&mut self, channel: DmaChannel, interrupt: DmaInterrupt) -> Result<()> {
931        enable_interrupt_internal(&mut self.regs, channel, interrupt)
932    }
933
934    /// Disable a specific type of interrupt.
935    /// todo: Non-H7 version too!
936    // #[cfg(feature = "h7")]
937    pub fn disable_interrupt(
938        &mut self,
939        channel: DmaChannel,
940        interrupt: DmaInterrupt,
941    ) -> Result<()> {
942        // Can only be set when the channel is disabled.
943        // todo: Is this true for disabling interrupts true, re the channel must be disabled?
944        #[cfg(feature = "h7")]
945        let cr = &self.regs.st(channel as usize).cr();
946        #[cfg(not(feature = "h7"))]
947        let cr = &self.regs.ch(channel as usize).cr();
948
949        let originally_enabled = cr.read().en().bit_is_set();
950
951        if originally_enabled {
952            cr.modify(|_, w| w.en().clear_bit());
953            bounded_loop!(cr.read().en().bit_is_set(), Error::RegisterUnchanged);
954        }
955
956        match interrupt {
957            DmaInterrupt::TransferError => cr.modify(|_, w| w.teie().clear_bit()),
958            DmaInterrupt::HalfTransfer => cr.modify(|_, w| w.htie().clear_bit()),
959            DmaInterrupt::TransferComplete => cr.modify(|_, w| w.tcie().clear_bit()),
960            #[cfg(feature = "h7")]
961            DmaInterrupt::DirectModeError => cr.modify(|_, w| w.dmeie().clear_bit()),
962            #[cfg(feature = "h7")]
963            DmaInterrupt::FifoError => self
964                .regs
965                .st(channel as usize)
966                .fcr()
967                .modify(|_, w| w.feie().clear_bit()),
968        };
969
970        if originally_enabled {
971            cr.modify(|_, w| w.en().bit(true));
972            bounded_loop!(cr.read().en().bit_is_clear(), Error::RegisterUnchanged);
973        }
974
975        Ok(())
976    }
977}
978
979/// Configure a DMA channel. See L4 RM 0394, section 11.4.4. Sets the Transfer Complete
980/// interrupt. This is the function called by various module `read_dma` and `write_dma` functions.
981// #[cfg(feature = "h7")]
982pub fn cfg_channel<D>(
983    regs: &mut D,
984    channel: DmaChannel,
985    periph_addr: u32,
986    mem_addr: u32,
987    num_data: u32,
988    direction: Direction,
989    periph_size: DataSize,
990    mem_size: DataSize,
991    cfg: ChannelCfg,
992) -> Result<()>
993where
994    D: Deref<Target = dma1::RegisterBlock>,
995{
996    cfg_if! {
997        if #[cfg(feature = "h7")] {
998            let mut channel = regs.st(channel as usize);
999        } else {
1000            let mut channel = regs.ch(channel as usize);
1001        }
1002    }
1003    // todo: The H7 sections are different, but we consolidated the comments. Figure out
1004    // todo what's different and fix it by following the steps
1005    // FIXME: Something is not right here.
1006
1007    let originally_enabled = channel.cr().read().en().bit_is_set();
1008
1009    channel.cr().modify(|_, w| w.en().clear_bit());
1010    bounded_loop!(
1011        channel.cr().read().en().bit_is_set(),
1012        Error::RegisterUnchanged
1013    );
1014
1015    // H743 RM Section 15.3.19 The following sequence is needed to configure a DMA stream x:
1016    // 1. Set the peripheral register address in the DMA_CPARx register.
1017    // The data is moved from/to this address to/from the memory after the peripheral event,
1018    // or after the channel is enabled in memory-to-memory mode.
1019    channel.par().write(|w| unsafe { w.bits(periph_addr) });
1020
1021    // See the [Embedonomicon section on DMA](https://docs.rust-embedded.org/embedonomicon/dma.html)
1022    // for info on why we use `compiler_fence` here:
1023    // "We use Ordering::Release to prevent all preceding memory operations from being moved
1024    // after [starting DMA], which performs a volatile write."
1025
1026    atomic::compiler_fence(Ordering::SeqCst);
1027
1028    // 2. Set the memory address in the DMA_CMARx register.
1029    // The data is written to/read from the memory after the peripheral event or after the
1030    // channel is enabled in memory-to-memory mode.
1031    #[cfg(any(feature = "h7", feature = "l5"))]
1032    channel.m0ar().write(|w| unsafe { w.bits(mem_addr) });
1033
1034    #[cfg(not(any(feature = "h7", feature = "l5")))]
1035    channel.mar().write(|w| unsafe { w.bits(mem_addr) });
1036
1037    // todo: m1ar too, if in double-buffer mode.
1038
1039    // 3. Configure the total number of data to transfer in the DMA_CNDTRx register.
1040    // After each data transfer, this value is decremented.
1041    channel.ndtr().write(|w| unsafe { w.bits(num_data) });
1042
1043    // (later): The circular mode must not be used in memory-to-memory mode. Before enabling a
1044    // channel in circular mode (CIRC = 1), the software must clear the MEM2MEM bit of the
1045    // DMA_CCRx register. When the circular mode is activated, the amount of data to transfer is
1046    // automatically reloaded with the initial value programmed during the channel configuration
1047    // phase, and the DMA requests continue to be served
1048
1049    // (See remainder of steps in `set_ccr()!` macro.
1050
1051    // todo: Let user set mem2mem mode?
1052
1053    if originally_enabled {
1054        channel.cr().modify(|_, w| w.en().clear_bit());
1055        bounded_loop!(
1056            channel.cr().read().en().bit_is_set(),
1057            Error::RegisterUnchanged
1058        );
1059    }
1060
1061    // 4. Configure the parameters listed below in the DMA_CCRx register:
1062    // (These are listed below by their corresponding reg write code)
1063    //
1064    // todo: See note about sep reg writes to disable channel, and when you need to do this.
1065
1066    channel.cr().modify(|_, w| unsafe {
1067        // – the channel priority
1068        w.pl().bits(cfg.priority as u8);
1069        // – the data transfer direction
1070        // This bit [DIR] must be set only in memory-to-peripheral and peripheral-to-memory modes.
1071        // 0: read from peripheral
1072        #[cfg(feature = "h7")]
1073        w.dir().bits(direction as u8);
1074        #[cfg(not(feature = "h7"))]
1075        w.dir().bit((direction as u8) != 0);
1076        // – the circular mode
1077        w.circ().bit(cfg.circular as u8 != 0);
1078        // – the peripheral and memory incremented mode
1079        w.pinc().bit(cfg.periph_incr as u8 != 0);
1080        w.minc().bit(cfg.mem_incr as u8 != 0);
1081        // – the peripheral and memory data size
1082        w.psize().bits(periph_size as u8);
1083        w.msize().bits(mem_size as u8);
1084        // – the interrupt enable at half and/or full transfer and/or transfer error
1085        w.tcie().bit(true);
1086        // (See `Step 5` above.)
1087        w.en().bit(true)
1088    });
1089
1090    // 5. Activate the channel by setting the EN bit in the DMA_CCRx register.
1091    // A channel, as soon as enabled, may serve any DMA request from the peripheral connected
1092    // to this channel, or may start a memory-to-memory block transfer.
1093    // Note: The two last steps of the channel configuration procedure may be merged into a single
1094    // access to the DMA_CCRx register, to configure and enable the channel.
1095    // When a channel is enabled and still active (not completed), the software must perform two
1096    // separate write accesses to the DMA_CCRx register, to disable the channel, then to
1097    // reprogram the channel for another next block transfer.
1098    // Some fields of the DMA_CCRx register are read-only when the EN bit is set to 1
1099
1100    if originally_enabled {
1101        channel.cr().modify(|_, w| w.en().set_bit());
1102        bounded_loop!(
1103            channel.cr().read().en().bit_is_clear(),
1104            Error::RegisterUnchanged
1105        );
1106    }
1107
1108    Ok(())
1109}
1110
1111/// Stop a DMA transfer, if in progress.
1112fn stop_internal<D>(regs: &mut D, channel: DmaChannel) -> Result<()>
1113where
1114    D: Deref<Target = dma1::RegisterBlock>,
1115{
1116    // L4 RM:
1117    // Once the software activates a channel, it waits for the completion of the programmed
1118    // transfer. The DMA controller is not able to resume an aborted active channel with a possible
1119    // suspended bus transfer.
1120    // To correctly stop and disable a channel, the software clears the EN bit of the DMA_CCRx
1121    // register.
1122
1123    // The software secures that no pending request from the peripheral is served by the
1124    // DMA controller before the transfer completion.
1125    // todo?
1126
1127    #[cfg(feature = "h7")]
1128    let cr = &regs.st(channel as usize).cr();
1129    #[cfg(not(feature = "h7"))]
1130    let cr = &regs.ch(channel as usize).cr();
1131
1132    cr.modify(|_, w| w.en().clear_bit());
1133    bounded_loop!(cr.read().en().bit_is_set(), Error::RegisterUnchanged);
1134
1135    Ok(())
1136
1137    // The software waits for the transfer complete or transfer error interrupt.
1138    // (Handed by calling code)
1139
1140    // (todo: set ifcr().cficx bit to clear all interrupts?)
1141
1142    // When a channel transfer error occurs, the EN bit of the DMA_CCRx register is cleared by
1143    // hardware. This EN bit can not be set again by software to re-activate the channel x, until the
1144    // TEIFx bit of the DMA_ISR register is set
1145}
1146
1147/// Stop a DMA transfer, if in progress.
1148pub fn stop(periph: DmaPeriph, channel: DmaChannel) -> Result<()> {
1149    match periph {
1150        DmaPeriph::Dma1 => {
1151            let mut regs = unsafe { &(*DMA1::ptr()) };
1152            stop_internal(&mut regs, channel)
1153        }
1154        #[cfg(dma2)]
1155        DmaPeriph::Dma2 => {
1156            let mut regs = unsafe { &(*DMA2::ptr()) };
1157            stop_internal(&mut regs, channel)
1158        }
1159    }
1160}
1161
1162fn clear_interrupt_internal<D>(
1163    regs: &mut D,
1164    channel: DmaChannel,
1165    interrupt: DmaInterrupt,
1166) -> Result<()>
1167where
1168    D: Deref<Target = dma1::RegisterBlock>,
1169{
1170    // todo: Add waiting on the set bit(s)?
1171    cfg_if! {
1172        if #[cfg(any(feature = "g4", feature = "wl"))] {
1173            regs.ifcr().write(|w| match channel {
1174                DmaChannel::C1 => match interrupt {
1175                    DmaInterrupt::TransferError => w.cteif1().bit(true),
1176                    DmaInterrupt::HalfTransfer => w.chtif1().bit(true),
1177                    DmaInterrupt::TransferComplete => w.ctcif1().bit(true),
1178                }
1179                DmaChannel::C2 => match interrupt {
1180                    DmaInterrupt::TransferError => w.cteif2().bit(true),
1181                    DmaInterrupt::HalfTransfer => w.chtif2().bit(true),
1182                    DmaInterrupt::TransferComplete => w.ctcif2().bit(true),
1183                }
1184                DmaChannel::C3 => match interrupt {
1185                    DmaInterrupt::TransferError => w.cteif3().bit(true),
1186                    DmaInterrupt::HalfTransfer => w.chtif3().bit(true),
1187                    DmaInterrupt::TransferComplete => w.ctcif3().bit(true),
1188                }
1189                DmaChannel::C4 => match interrupt {
1190                    DmaInterrupt::TransferError => w.cteif4().bit(true),
1191                    DmaInterrupt::HalfTransfer => w.chtif4().bit(true),
1192                    DmaInterrupt::TransferComplete => w.ctcif4().bit(true),
1193                }
1194                DmaChannel::C5 => match interrupt {
1195                    DmaInterrupt::TransferError => w.cteif5().bit(true),
1196                    DmaInterrupt::HalfTransfer => w.chtif5().bit(true),
1197                    DmaInterrupt::TransferComplete => w.ctcif5().bit(true),
1198                }
1199                DmaChannel::C6 => match interrupt {
1200                    DmaInterrupt::TransferError => w.cteif6().bit(true),
1201                    DmaInterrupt::HalfTransfer => w.chtif6().bit(true),
1202                    DmaInterrupt::TransferComplete => w.ctcif6().bit(true),
1203                }
1204                DmaChannel::C7 => match interrupt {
1205                    DmaInterrupt::TransferError => w.cteif7().bit(true),
1206                    DmaInterrupt::HalfTransfer => w.chtif7().bit(true),
1207                    DmaInterrupt::TransferComplete => w.ctcif7().bit(true),
1208                }
1209                #[cfg(not(feature = "wl"))]
1210                DmaChannel::C8 => match interrupt {
1211                    DmaInterrupt::TransferError => w.cteif8().bit(true),
1212                    DmaInterrupt::HalfTransfer => w.chtif8().bit(true),
1213                    DmaInterrupt::TransferComplete => w.ctcif8().bit(true),
1214                }
1215            });
1216        } else if #[cfg(feature = "h7")] {
1217            match channel {
1218                DmaChannel::C0 => match interrupt {
1219                    DmaInterrupt::TransferError => regs.lifcr().write(|w| w.cteif0().bit(true)),
1220                    DmaInterrupt::HalfTransfer => regs.lifcr().write(|w| w.chtif0().bit(true)),
1221                    DmaInterrupt::TransferComplete => regs.lifcr().write(|w| w.ctcif0().bit(true)),
1222                    DmaInterrupt::DirectModeError => regs.lifcr().write(|w| w.cdmeif0().bit(true)),
1223                    DmaInterrupt::FifoError => regs.lifcr().write(|w| w.cfeif0().bit(true)),
1224                }
1225                DmaChannel::C1 => match interrupt {
1226                    DmaInterrupt::TransferError => regs.lifcr().write(|w| w.cteif1().bit(true)),
1227                    DmaInterrupt::HalfTransfer => regs.lifcr().write(|w| w.chtif1().bit(true)),
1228                    DmaInterrupt::TransferComplete => regs.lifcr().write(|w| w.ctcif1().bit(true)),
1229                    DmaInterrupt::DirectModeError => regs.lifcr().write(|w| w.cdmeif1().bit(true)),
1230                    DmaInterrupt::FifoError => regs.lifcr().write(|w| w.cfeif1().bit(true)),
1231                }
1232                DmaChannel::C2 => match interrupt {
1233                    DmaInterrupt::TransferError => regs.lifcr().write(|w| w.cteif2().bit(true)),
1234                    DmaInterrupt::HalfTransfer => regs.lifcr().write(|w| w.chtif2().bit(true)),
1235                    DmaInterrupt::TransferComplete => regs.lifcr().write(|w| w.ctcif2().bit(true)),
1236                    DmaInterrupt::DirectModeError => regs.lifcr().write(|w| w.cdmeif2().bit(true)),
1237                    DmaInterrupt::FifoError => regs.lifcr().write(|w| w.cfeif2().bit(true)),
1238                }
1239                DmaChannel::C3 => match interrupt {
1240                    DmaInterrupt::TransferError => regs.lifcr().write(|w| w.cteif3().bit(true)),
1241                    DmaInterrupt::HalfTransfer => regs.lifcr().write(|w| w.chtif3().bit(true)),
1242                    DmaInterrupt::TransferComplete => regs.lifcr().write(|w| w.ctcif3().bit(true)),
1243                    DmaInterrupt::DirectModeError => regs.lifcr().write(|w| w.cdmeif3().bit(true)),
1244                    DmaInterrupt::FifoError => regs.lifcr().write(|w| w.cfeif3().bit(true)),
1245                }
1246                DmaChannel::C4 => match interrupt {
1247                    DmaInterrupt::TransferError => regs.hifcr().write(|w| w.cteif4().bit(true)),
1248                    DmaInterrupt::HalfTransfer => regs.hifcr().write(|w| w.chtif4().bit(true)),
1249                    DmaInterrupt::TransferComplete => regs.hifcr().write(|w| w.ctcif4().bit(true)),
1250                    DmaInterrupt::DirectModeError => regs.hifcr().write(|w| w.cdmeif4().bit(true)),
1251                    DmaInterrupt::FifoError => regs.hifcr().write(|w| w.cfeif4().bit(true)),
1252                }
1253                DmaChannel::C5 => match interrupt {
1254                    DmaInterrupt::TransferError => regs.hifcr().write(|w| w.cteif5().bit(true)),
1255                    DmaInterrupt::HalfTransfer => regs.hifcr().write(|w| w.chtif5().bit(true)),
1256                    DmaInterrupt::TransferComplete => regs.hifcr().write(|w| w.ctcif5().bit(true)),
1257                    DmaInterrupt::DirectModeError => regs.hifcr().write(|w| w.cdmeif5().bit(true)),
1258                    DmaInterrupt::FifoError => regs.hifcr().write(|w| w.cfeif5().bit(true)),
1259                }
1260                DmaChannel::C6 => match interrupt {
1261                    DmaInterrupt::TransferError => regs.hifcr().write(|w| w.cteif6().bit(true)),
1262                    DmaInterrupt::HalfTransfer => regs.hifcr().write(|w| w.chtif6().bit(true)),
1263                    DmaInterrupt::TransferComplete => regs.hifcr().write(|w| w.ctcif6().bit(true)),
1264                    DmaInterrupt::DirectModeError => regs.hifcr().write(|w| w.cdmeif6().bit(true)),
1265                    DmaInterrupt::FifoError => regs.hifcr().write(|w| w.cfeif6().bit(true)),
1266                }
1267                DmaChannel::C7 => match interrupt {
1268                    DmaInterrupt::TransferError => regs.hifcr().write(|w| w.cteif7().bit(true)),
1269                    DmaInterrupt::HalfTransfer => regs.hifcr().write(|w| w.chtif7().bit(true)),
1270                    DmaInterrupt::TransferComplete => regs.hifcr().write(|w| w.ctcif7().bit(true)),
1271                    DmaInterrupt::DirectModeError => regs.hifcr().write(|w| w.cdmeif7().bit(true)),
1272                    DmaInterrupt::FifoError => regs.hifcr().write(|w| w.cfeif7().bit(true)),
1273                }
1274            };
1275            // todo: G0 PAC 0.14 had a reversion where these flags used to work, but now don't.
1276        } else if #[cfg(not(feature = "g0"))] {
1277            regs.ifcr().write(|w| match channel {
1278                DmaChannel::C1 => match interrupt {
1279                    DmaInterrupt::TransferError => w.cteif1().bit(true),
1280                    DmaInterrupt::HalfTransfer => w.chtif1().bit(true),
1281                    DmaInterrupt::TransferComplete => w.ctcif1().bit(true),
1282                }
1283                DmaChannel::C2 => match interrupt {
1284                    DmaInterrupt::TransferError => w.cteif2().bit(true),
1285                    DmaInterrupt::HalfTransfer => w.chtif2().bit(true),
1286                    DmaInterrupt::TransferComplete => w.ctcif2().bit(true),
1287                }
1288                DmaChannel::C3 => match interrupt {
1289                    DmaInterrupt::TransferError => w.cteif3().bit(true),
1290                    DmaInterrupt::HalfTransfer => w.chtif3().bit(true),
1291                    DmaInterrupt::TransferComplete => w.ctcif3().bit(true),
1292                }
1293                #[cfg(not(any(feature = "c011", feature = "c031")))]
1294                DmaChannel::C4 => match interrupt {
1295                    DmaInterrupt::TransferError => w.cteif4().bit(true),
1296                    DmaInterrupt::HalfTransfer => w.chtif4().bit(true),
1297                    DmaInterrupt::TransferComplete => w.ctcif4().bit(true),
1298                }
1299                #[cfg(not(any(feature = "c011", feature = "c031")))]
1300                DmaChannel::C5 => match interrupt {
1301                    DmaInterrupt::TransferError => w.cteif5().bit(true),
1302                    DmaInterrupt::HalfTransfer => w.chtif5().bit(true),
1303                    DmaInterrupt::TransferComplete => w.ctcif5().bit(true),
1304                }
1305                #[cfg(not(any(feature = "g0", feature = "c0")))]
1306                DmaChannel::C6 => match interrupt {
1307                    DmaInterrupt::TransferError => w.cteif6().bit(true),
1308                    DmaInterrupt::HalfTransfer => w.chtif6().bit(true),
1309                    DmaInterrupt::TransferComplete => w.ctcif6().bit(true),
1310                }
1311                #[cfg(not(any(feature = "g0", feature = "c0")))]
1312                DmaChannel::C7 => match interrupt {
1313                    DmaInterrupt::TransferError => w.cteif7().bit(true),
1314                    DmaInterrupt::HalfTransfer => w.chtif7().bit(true),
1315                    DmaInterrupt::TransferComplete => w.ctcif7().bit(true),
1316                }
1317                #[cfg(any(feature = "l5", feature = "g4"))]
1318                DmaChannel::C8 => match interrupt {
1319                    DmaInterrupt::TransferError => w.cteif8().bit(true),
1320                    DmaInterrupt::HalfTransfer => w.chtif8().bit(true),
1321                    DmaInterrupt::TransferComplete => w.ctcif8().bit(true),
1322                }
1323            });
1324        }
1325    }
1326    Ok(())
1327}
1328
1329fn enable_interrupt_internal<D>(
1330    regs: &mut D,
1331    channel: DmaChannel,
1332    interrupt: DmaInterrupt,
1333) -> Result<()>
1334where
1335    D: Deref<Target = dma1::RegisterBlock>,
1336{
1337    // Can only be set when the channel is disabled.
1338    #[cfg(feature = "h7")]
1339    let cr = &regs.st(channel as usize).cr();
1340    #[cfg(not(feature = "h7"))]
1341    let cr = &regs.ch(channel as usize).cr();
1342
1343    match interrupt {
1344        DmaInterrupt::TransferError => cr.modify(|_, w| w.teie().bit(true)),
1345        DmaInterrupt::HalfTransfer => cr.modify(|_, w| w.htie().bit(true)),
1346        DmaInterrupt::TransferComplete => cr.modify(|_, w| w.tcie().bit(true)),
1347        #[cfg(feature = "h7")]
1348        DmaInterrupt::DirectModeError => cr.modify(|_, w| w.dmeie().bit(true)),
1349        #[cfg(feature = "h7")]
1350        DmaInterrupt::FifoError => regs
1351            .st(channel as usize)
1352            .fcr()
1353            .modify(|_, w| w.feie().bit(true)),
1354    };
1355
1356    Ok(())
1357}
1358
1359fn disable_interrupt_internal<D>(
1360    regs: &mut D,
1361    channel: DmaChannel,
1362    interrupt: DmaInterrupt,
1363) -> Result<()>
1364where
1365    D: Deref<Target = dma1::RegisterBlock>,
1366{
1367    // Can only be set when the channel is disabled.
1368    #[cfg(feature = "h7")]
1369    let cr = &regs.st(channel as usize).cr();
1370    #[cfg(not(feature = "h7"))]
1371    let cr = &regs.ch(channel as usize).cr();
1372
1373    match interrupt {
1374        DmaInterrupt::TransferError => cr.modify(|_, w| w.teie().clear_bit()),
1375        DmaInterrupt::HalfTransfer => cr.modify(|_, w| w.htie().clear_bit()),
1376        DmaInterrupt::TransferComplete => cr.modify(|_, w| w.tcie().clear_bit()),
1377        #[cfg(feature = "h7")]
1378        DmaInterrupt::DirectModeError => cr.modify(|_, w| w.dmeie().clear_bit()),
1379        #[cfg(feature = "h7")]
1380        DmaInterrupt::FifoError => regs
1381            .st(channel as usize)
1382            .fcr()
1383            .modify(|_, w| w.feie().clear_bit()),
1384    };
1385
1386    Ok(())
1387}
1388
1389/// Enable a specific type of interrupt.
1390pub fn enable_interrupt(
1391    periph: DmaPeriph,
1392    channel: DmaChannel,
1393    interrupt: DmaInterrupt,
1394) -> Result<()> {
1395    match periph {
1396        DmaPeriph::Dma1 => {
1397            let mut regs = unsafe { &(*DMA1::ptr()) };
1398            enable_interrupt_internal(&mut regs, channel, interrupt)
1399        }
1400        #[cfg(dma2)]
1401        DmaPeriph::Dma2 => {
1402            let mut regs = unsafe { &(*DMA2::ptr()) };
1403            enable_interrupt_internal(&mut regs, channel, interrupt)
1404        }
1405    }
1406}
1407
1408/// Disable a specific type of interrupt.
1409pub fn disable_interrupt(
1410    periph: DmaPeriph,
1411    channel: DmaChannel,
1412    interrupt: DmaInterrupt,
1413) -> Result<()> {
1414    match periph {
1415        DmaPeriph::Dma1 => {
1416            let mut regs = unsafe { &(*DMA1::ptr()) };
1417            disable_interrupt_internal(&mut regs, channel, interrupt)
1418        }
1419        #[cfg(dma2)]
1420        DmaPeriph::Dma2 => {
1421            let mut regs = unsafe { &(*DMA2::ptr()) };
1422            disable_interrupt_internal(&mut regs, channel, interrupt)
1423        }
1424    }
1425}
1426
1427/// Clear an interrupt flag.
1428pub fn clear_interrupt(
1429    periph: DmaPeriph,
1430    channel: DmaChannel,
1431    interrupt: DmaInterrupt,
1432) -> Result<()> {
1433    match periph {
1434        DmaPeriph::Dma1 => {
1435            let mut regs = unsafe { &(*DMA1::ptr()) };
1436            clear_interrupt_internal(&mut regs, channel, interrupt)
1437        }
1438        #[cfg(dma2)]
1439        DmaPeriph::Dma2 => {
1440            let mut regs = unsafe { &(*DMA2::ptr()) };
1441            clear_interrupt_internal(&mut regs, channel, interrupt)
1442        }
1443    }
1444}
1445
1446#[cfg(any(
1447    feature = "l5",
1448    feature = "g0",
1449    feature = "g4",
1450    feature = "h7",
1451    feature = "wb",
1452    feature = "wl",
1453))]
1454/// Configure a specific DMA channel to work with a specific peripheral.
1455pub fn mux(periph: DmaPeriph, channel: DmaChannel, input: DmaInput) {
1456    // Note: This is similar in API and purpose to `channel_select` above,
1457    // for different families. We're keeping it as a separate function instead
1458    // of feature-gating within the same function so the name can be recognizable
1459    // from the RM etc.
1460
1461    // G4 example:
1462    // "The mapping of resources to DMAMUX is hardwired.
1463    // DMAMUX is used with DMA1 and DMA2:
1464    // For category 3 and category 4 devices:
1465    // • DMAMUX channels 0 to 7 are connected to DMA1 channels 1 to 8
1466    // • DMAMUX channels 8 to 15 are connected to DMA2 channels 1 to 8
1467    //
1468    // For category 2 devices:
1469    // • DMAMUX channels 0 to 5 are connected to DMA1 channels 1 to 6
1470    // • DMAMUX channels 6 to 11 are connected to DMA2 channels 1 to 6"
1471    //
1472    // H723/25/33/35"
1473    // DMAMUX1 is used with DMA1 and DMA2 in D2 domain
1474    // • DMAMUX1 channels 0 to 7 are connected to DMA1 channels 0 to 7
1475    // • DMAMUX1 channels 8 to 15 are connected to DMA2 channels 0 to 7
1476    // (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.)
1477
1478    // todo: With this in mind, some of the mappings below are not correct on some G4 variants.
1479
1480    unsafe {
1481        let mux = unsafe { &(*DMAMUX::ptr()) };
1482
1483        #[cfg(feature = "g4")]
1484        let rcc = unsafe { &(*RCC::ptr()) };
1485        #[cfg(feature = "g4")]
1486        rcc.ahb1enr().modify(|_, w| w.dmamux1en().bit(true));
1487
1488        // Note the offset by 1, due to mismatch in DMA channels starting at 1, and DMAMUX
1489        // channels starting at 0. Ops tested this is correct on G4.
1490
1491        // G4 RM: "For category 3 and category 4 devices:
1492        // - DMAMUX channels 0 to 7 are connected to DMA1 channels 1 to 8
1493        // - DMAMUX channels 8 to 15 are connected to DMA2 channels 1 to 8"
1494        // For category 2 devices (G431 etc):
1495        // - DMAMUX channels 0 to 5 are connected to DMA1 channels 1 to 6
1496        // - DMAMUX channels 6 to 11 are connected to DMA2 channels 1 to 6
1497
1498        // todo: Setting to +8 for G431 for now, while TS other issues; I believe
1499        // todo that's how it was set previously.
1500
1501        // L5 RM: Same as cat 3/4 G4 devs above, but connected to DMA chs 0-7 respectively.
1502        #[cfg(feature = "g431")]
1503        // todo: I believe this should be 6 from the RM, but in practice, 8 works and 6 doesn't.
1504        let dma2_offset = 8;
1505        #[cfg(not(feature = "g431"))]
1506        let dma2_offset = 8;
1507
1508        match periph {
1509            DmaPeriph::Dma1 => {
1510                mux.ccr(channel as usize)
1511                    .modify(|_, w| w.dmareq_id().bits(input as u8));
1512            }
1513            #[cfg(dma2)]
1514            DmaPeriph::Dma2 => {
1515                mux.ccr(channel as usize + dma2_offset)
1516                    .modify(|_, w| w.dmareq_id().bits(input as u8));
1517            }
1518        }
1519    }
1520}
1521
1522#[cfg(feature = "h7")]
1523/// Configure a specific DMA channel to work with a specific peripheral, on DMAMUX2.
1524pub fn mux2(periph: DmaPeriph, channel: DmaChannel, input: DmaInput2, mux: &mut DMAMUX2) {
1525    mux.ccr(channel as usize)
1526        .modify(|_, w| unsafe { w.dmareq_id().bits(input as u8) });
1527}
1528
1529// todo: Enable this for other MCUs as requried
1530/// Enable the DMA mux RCC clock. Applicable to some variants, but no others. (H7 and G0 don't use it,
1531/// for example)
1532#[cfg(any(feature = "g4", feature = "wb"))]
1533pub fn enable_mux1() {
1534    let rcc = unsafe { &(*RCC::ptr()) };
1535
1536    cfg_if! {
1537        if #[cfg(feature = "g4")] {
1538            // Note inconsistency between `dmamux` and `dmamux`; can't use macro here.
1539            rcc.ahb1enr().modify(|_, w| w.dmamux1en().bit(true));
1540            rcc.ahb1rstr().modify(|_, w| w.dmamux1rst().bit(true));
1541            rcc.ahb1rstr().modify(|_, w| w.dmamux1rst().clear_bit());
1542        } else {
1543            rcc_en_reset!(ahb1, dmamux, rcc);
1544        }
1545    }
1546}
1547
1548#[cfg(feature = "l4")] // Only required on L4
1549/// Select which peripheral on a given channel we're using.
1550/// See L44 RM, Table 41.
1551pub(crate) fn channel_select<D>(regs: &mut D, input: DmaInput)
1552where
1553    D: Deref<Target = dma1::RegisterBlock>,
1554{
1555    // todo: Allow selecting channels in pairs to save a write.
1556    let val = input.dma1_channel_select();
1557
1558    unsafe {
1559        regs.cselr().modify(|_, w| match input.dma1_channel() {
1560            DmaChannel::C1 => w.c1s().bits(val),
1561            DmaChannel::C2 => w.c2s().bits(val),
1562            DmaChannel::C3 => w.c3s().bits(val),
1563            DmaChannel::C4 => w.c4s().bits(val),
1564            DmaChannel::C5 => w.c5s().bits(val),
1565            DmaChannel::C6 => w.c6s().bits(val),
1566            DmaChannel::C7 => w.c7s().bits(val),
1567        });
1568    }
1569}
1570
1571// todo: Code below is for experimental struct-per-channel API
1572macro_rules! make_chan_struct {
1573    // ($Periph:ident, $PERIPH:ident, $periph:ident, $ch:expr) => {
1574    ($periph: expr, $ch:expr) => {
1575        paste::paste! {
1576            /// Experimental/WIP channel-based DMA struct.
1577            pub struct [<Dma $periph Ch $ch>] {
1578                // #[cfg(feature = "h7")]
1579                // regs: dma1::st // todo?
1580            }
1581
1582            impl [<Dma $periph Ch $ch>] {
1583                /// Initialize a DMA peripheral, including enabling and resetting
1584                /// its RCC peripheral clock.
1585                /// Note that the clock may have already been enabled by a different channel's
1586                /// constructor.
1587                pub fn new() -> Self {
1588                    // todo: Enable RCC for DMA 2 etc!
1589                    let rcc = unsafe { &(*RCC::ptr()) };
1590                    cfg_if! {
1591                        if #[cfg(feature = "f3")] {
1592                            rcc.ahbenr().modify(|_, w| w.dma1en().bit(true)); // no dmarst on F3.
1593                        } else if #[cfg(feature = "g0")] {
1594                            rcc_en_reset!(ahb1, dma, rcc);
1595                        } else {
1596                            rcc_en_reset!(ahb1, [<dma $periph>], rcc);
1597                        }
1598                    }
1599
1600                    Self { }
1601                }
1602
1603                fn regs(&self) -> &[<dma $periph>]::RegisterBlock {
1604                    unsafe { &(*[<DMA $periph>]::ptr())}
1605                }
1606
1607                // // #[cfg(feature = "h7")]
1608                // fn ccr(&self) -> &[<dma $periph>]::st::CR {
1609                // // fn ccr(&self) -> &u8 {
1610                //     #[cfg(feature = "h7")]
1611                //     &self.regs().st($ch).cr
1612                //     #[cfg(not(feature = "h7"))]
1613                //     &self.regs().ch($ch).cr
1614                // }z
1615                //
1616                // // #[cfg(not(any(feature = "h7", feature = "f3", feature = "g0")))]
1617                // // fn ccr(&self) -> &[<dma $periph>]::[<CCR $ch>] {
1618                // //     &self.regs().[<ccr $ch>]
1619                // // }
1620                //
1621                // #[cfg(any(feature = "f3", feature = "g0"))]
1622                // // fn ccr(&self) -> &[<dma $periph>]::ch::cr {
1623                //  fn ccr(&self) -> i8 {
1624                //     &self.regs().[<ch $ch>].cr
1625                // }
1626
1627                // #[cfg(not(feature = "h7"))] // due to num_data size diff
1628                // /// Configure a DMA channel. See L4 RM 0394, section 11.4.4. Sets the Transfer Complete
1629                // /// interrupt. Note that this fn has been (perhaps) depreciated by the standalone fn.
1630                // pub fn cfg_channel(
1631                //     &mut self,
1632                //     periph_addr: u32,
1633                //     mem_addr: u32,
1634                //     // num_data: u16,
1635                //     num_data: u32,
1636                //     direction: Direction,
1637                //     periph_size: DataSize,
1638                //     mem_size: DataSize,
1639                //     cfg: ChannelCfg,
1640                // ) {
1641                //     cfg_channel(
1642                //         &mut self.regs(),
1643                //         DmaChannel::[<C $ch>],
1644                //         periph_addr,
1645                //         mem_addr,
1646                //         num_data,
1647                //         direction,
1648                //         periph_size,
1649                //         mem_size,
1650                //         cfg,
1651                //     )
1652                // }
1653
1654                /// Configure a DMA channel. See L4 RM 0394, section 11.4.4. Sets the Transfer Complete
1655                /// interrupt. Note that this fn has been (perhaps) depreciated by the standalone fn.
1656                pub fn cfg_channel(
1657                    &mut self,
1658                    periph_addr: u32,
1659                    mem_addr: u32,
1660                    num_data: u32,
1661                    direction: Direction,
1662                    periph_size: DataSize,
1663                    mem_size: DataSize,
1664                    cfg: ChannelCfg,
1665                ) -> Result<()> {
1666                    cfg_channel(
1667                        &mut self.regs(),
1668                        DmaChannel::[<C $ch>],
1669                        periph_addr,
1670                        mem_addr,
1671                        num_data,
1672                        direction,
1673                        periph_size,
1674                        mem_size,
1675                        cfg,
1676                    )
1677                }
1678
1679                /// Stop a DMA transfer, if in progress.
1680                pub fn stop(&mut self) -> Result<()> {
1681                    #[cfg(feature = "h7")]
1682                    let ccr = self.regs().st($ch).cr();
1683                    #[cfg(not(feature = "h7"))]
1684                    let ccr = self.regs().ch($ch).cr();
1685
1686                    ccr.modify(|_, w| w.en().clear_bit());
1687                    bounded_loop!(ccr.read().en().bit_is_set(), Error::RegisterUnchanged);
1688
1689                    Ok(())
1690                }
1691
1692                /// Enable a specific type of interrupt.
1693                pub fn enable_interrupt(&mut self, interrupt: DmaInterrupt) {
1694                    enable_interrupt_internal(&mut self.regs(), DmaChannel::[<C $ch>], interrupt).unwrap()
1695                }
1696
1697                /// Clear an interrupt flag.
1698                pub fn clear_interrupt(&mut self, interrupt: DmaInterrupt) {
1699                    clear_interrupt_internal(&mut self.regs(), DmaChannel::[<C $ch>], interrupt).unwrap()
1700                }
1701                // todo: Other methods.
1702            }
1703        }
1704    };
1705}
1706
1707// Note: G0 is limited, eg for some variants only up to DMA1, ch5.
1708cfg_if! {
1709    if #[cfg(not(any(feature = "f3", feature = "g0")))] {
1710        #[cfg(feature = "h7")]
1711        make_chan_struct!(1, 0);
1712        make_chan_struct!(1, 1);
1713        make_chan_struct!(1, 2);
1714        make_chan_struct!(1, 3);
1715        #[cfg(not(any(feature = "c011", feature = "c031")))]
1716        make_chan_struct!(1, 4);
1717        #[cfg(not(any(feature = "c011", feature = "c031")))]
1718        make_chan_struct!(1, 5);
1719        #[cfg(not(any(feature = "g0", feature = "c0")))]
1720        make_chan_struct!(1, 6);
1721        #[cfg(not(any(feature = "g0", feature = "c0")))]
1722        make_chan_struct!(1, 7);
1723        #[cfg(any(feature = "l5", feature = "g4"))]
1724        make_chan_struct!(1, 8);
1725
1726        #[cfg(feature = "h7")]
1727        make_chan_struct!(2, 0);
1728        #[cfg(not(any(feature = "g0", feature = "wb", feature = "c0")))]
1729        make_chan_struct!(2, 1);
1730        #[cfg(not(any(feature = "g0", feature = "wb", feature = "c0")))]
1731        make_chan_struct!(2, 2);
1732        #[cfg(not(any(feature = "g0", feature = "wb", feature = "c0")))]
1733        make_chan_struct!(2, 3);
1734        #[cfg(not(any(feature = "g0", feature = "wb", feature = "c0")))]
1735        make_chan_struct!(2, 4);
1736        #[cfg(not(any(feature = "g0", feature = "wb", feature = "c0")))]
1737        make_chan_struct!(2, 5);
1738        #[cfg(not(any(feature = "g0", feature = "wb", feature = "c0")))]
1739        make_chan_struct!(2, 6);
1740        #[cfg(not(any(feature = "g0", feature = "wb", feature = "c0")))]
1741        make_chan_struct!(2, 7);
1742        #[cfg(any(feature = "l5", feature = "g4"))]
1743        make_chan_struct!(2, 8);
1744    }
1745}