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