esp_hal/dma/
gdma.rs

1//! # General Direct Memory Access (GMDA)
2//!
3//! ## Overview
4//! GDMA is a feature that allows peripheral-to-memory, memory-to-peripheral,
5//! and memory-to-memory data transfer at high speed. The CPU is not involved in
6//! the GDMA transfer and therefore is more efficient with less workload.
7//!
8//! The `GDMA` module provides multiple DMA channels, each capable of managing
9//! data transfer for various peripherals.
10//!
11//! ## Configuration
12//! GDMA peripheral can be initializes using the `new` function, which requires
13//! a DMA peripheral instance and a clock control reference.
14//!
15//! <em>PS: Note that the number of DMA channels is chip-specific.</em>
16
17use critical_section::CriticalSection;
18
19use crate::{
20    dma::*,
21    handler,
22    interrupt::Priority,
23    peripheral::{Peripheral, PeripheralRef},
24    peripherals::{pac, Interrupt, DMA},
25};
26
27/// An arbitrary GDMA channel
28#[derive(Debug)]
29#[cfg_attr(feature = "defmt", derive(defmt::Format))]
30pub struct AnyGdmaChannel(u8);
31
32impl Peripheral for AnyGdmaChannel {
33    type P = Self;
34
35    unsafe fn clone_unchecked(&self) -> Self::P {
36        Self(self.0)
37    }
38}
39
40impl crate::private::Sealed for AnyGdmaChannel {}
41impl DmaChannel for AnyGdmaChannel {
42    type Rx = AnyGdmaRxChannel;
43    type Tx = AnyGdmaTxChannel;
44
45    unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx) {
46        (AnyGdmaRxChannel(self.0), AnyGdmaTxChannel(self.0))
47    }
48}
49
50/// An arbitrary GDMA RX channel
51#[derive(Debug)]
52#[cfg_attr(feature = "defmt", derive(defmt::Format))]
53pub struct AnyGdmaRxChannel(u8);
54
55impl Peripheral for AnyGdmaRxChannel {
56    type P = Self;
57
58    unsafe fn clone_unchecked(&self) -> Self::P {
59        Self(self.0)
60    }
61}
62
63impl DmaChannelConvert<AnyGdmaRxChannel> for AnyGdmaRxChannel {
64    fn degrade(self) -> AnyGdmaRxChannel {
65        self
66    }
67}
68
69/// An arbitrary GDMA TX channel
70#[derive(Debug)]
71#[cfg_attr(feature = "defmt", derive(defmt::Format))]
72pub struct AnyGdmaTxChannel(u8);
73
74impl Peripheral for AnyGdmaTxChannel {
75    type P = Self;
76
77    unsafe fn clone_unchecked(&self) -> Self::P {
78        Self(self.0)
79    }
80}
81
82impl DmaChannelConvert<AnyGdmaTxChannel> for AnyGdmaTxChannel {
83    fn degrade(self) -> AnyGdmaTxChannel {
84        self
85    }
86}
87
88use crate::asynch::AtomicWaker;
89
90static TX_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT];
91static RX_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT];
92
93cfg_if::cfg_if! {
94    if #[cfg(any(esp32c2, esp32c3))] {
95        use portable_atomic::AtomicBool;
96        static TX_IS_ASYNC: [AtomicBool; CHANNEL_COUNT] = [const { AtomicBool::new(false) }; CHANNEL_COUNT];
97        static RX_IS_ASYNC: [AtomicBool; CHANNEL_COUNT] = [const { AtomicBool::new(false) }; CHANNEL_COUNT];
98    }
99}
100
101impl crate::private::Sealed for AnyGdmaTxChannel {}
102impl DmaTxChannel for AnyGdmaTxChannel {}
103
104impl AnyGdmaTxChannel {
105    #[inline(always)]
106    fn ch(&self) -> &pac::dma::ch::CH {
107        DMA::regs().ch(self.0 as usize)
108    }
109
110    #[cfg(any(esp32c2, esp32c3))]
111    #[inline(always)]
112    fn int(&self) -> &pac::dma::int_ch::INT_CH {
113        DMA::regs().int_ch(self.0 as usize)
114    }
115    #[inline(always)]
116    #[cfg(any(esp32c6, esp32h2))]
117    fn int(&self) -> &pac::dma::out_int_ch::OUT_INT_CH {
118        DMA::regs().out_int_ch(self.0 as usize)
119    }
120    #[cfg(esp32s3)]
121    #[inline(always)]
122    fn int(&self) -> &pac::dma::ch::out_int::OUT_INT {
123        DMA::regs().ch(self.0 as usize).out_int()
124    }
125}
126
127impl RegisterAccess for AnyGdmaTxChannel {
128    fn reset(&self) {
129        let conf0 = self.ch().out_conf0();
130        conf0.modify(|_, w| w.out_rst().set_bit());
131        conf0.modify(|_, w| w.out_rst().clear_bit());
132    }
133
134    fn set_burst_mode(&self, burst_mode: BurstConfig) {
135        self.ch()
136            .out_conf0()
137            .modify(|_, w| w.out_data_burst_en().bit(burst_mode.is_burst_enabled()));
138    }
139
140    fn set_descr_burst_mode(&self, burst_mode: bool) {
141        self.ch()
142            .out_conf0()
143            .modify(|_, w| w.outdscr_burst_en().bit(burst_mode));
144    }
145
146    fn set_priority(&self, priority: DmaPriority) {
147        self.ch()
148            .out_pri()
149            .write(|w| unsafe { w.tx_pri().bits(priority as u8) });
150    }
151
152    fn set_peripheral(&self, peripheral: u8) {
153        self.ch()
154            .out_peri_sel()
155            .modify(|_, w| unsafe { w.peri_out_sel().bits(peripheral) });
156    }
157
158    fn set_link_addr(&self, address: u32) {
159        self.ch()
160            .out_link()
161            .modify(|_, w| unsafe { w.outlink_addr().bits(address) });
162    }
163
164    fn start(&self) {
165        self.ch()
166            .out_link()
167            .modify(|_, w| w.outlink_start().set_bit());
168    }
169
170    fn stop(&self) {
171        self.ch()
172            .out_link()
173            .modify(|_, w| w.outlink_stop().set_bit());
174    }
175
176    fn restart(&self) {
177        self.ch()
178            .out_link()
179            .modify(|_, w| w.outlink_restart().set_bit());
180    }
181
182    fn set_check_owner(&self, check_owner: Option<bool>) {
183        self.ch()
184            .out_conf1()
185            .modify(|_, w| w.out_check_owner().bit(check_owner.unwrap_or(true)));
186    }
187
188    #[cfg(esp32s3)]
189    fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize) {
190        self.ch()
191            .out_conf1()
192            .modify(|_, w| unsafe { w.out_ext_mem_bk_size().bits(size as u8) });
193    }
194
195    #[cfg(psram_dma)]
196    fn can_access_psram(&self) -> bool {
197        true
198    }
199}
200
201impl TxRegisterAccess for AnyGdmaTxChannel {
202    fn is_fifo_empty(&self) -> bool {
203        cfg_if::cfg_if! {
204            if #[cfg(esp32s3)] {
205                 self.ch().outfifo_status().read().outfifo_empty_l3().bit_is_set()
206            } else {
207                 self.ch().outfifo_status().read().outfifo_empty().bit_is_set()
208            }
209        }
210    }
211
212    fn set_auto_write_back(&self, enable: bool) {
213        self.ch()
214            .out_conf0()
215            .modify(|_, w| w.out_auto_wrback().bit(enable));
216    }
217
218    fn last_dscr_address(&self) -> usize {
219        self.ch()
220            .out_eof_des_addr()
221            .read()
222            .out_eof_des_addr()
223            .bits() as _
224    }
225
226    fn async_handler(&self) -> Option<InterruptHandler> {
227        match self.0 {
228            0 => DmaChannel0::handler_out(),
229            #[cfg(not(esp32c2))]
230            1 => DmaChannel1::handler_out(),
231            #[cfg(not(esp32c2))]
232            2 => DmaChannel2::handler_out(),
233            #[cfg(esp32s3)]
234            3 => DmaChannel3::handler_out(),
235            #[cfg(esp32s3)]
236            4 => DmaChannel4::handler_out(),
237            _ => unreachable!(),
238        }
239    }
240
241    fn peripheral_interrupt(&self) -> Option<Interrupt> {
242        match self.0 {
243            0 => DmaChannel0::isr_out(),
244            #[cfg(not(esp32c2))]
245            1 => DmaChannel1::isr_out(),
246            #[cfg(not(esp32c2))]
247            2 => DmaChannel2::isr_out(),
248            #[cfg(esp32s3)]
249            3 => DmaChannel3::isr_out(),
250            #[cfg(esp32s3)]
251            4 => DmaChannel4::isr_out(),
252            _ => unreachable!(),
253        }
254    }
255}
256
257impl InterruptAccess<DmaTxInterrupt> for AnyGdmaTxChannel {
258    fn enable_listen(&self, interrupts: EnumSet<DmaTxInterrupt>, enable: bool) {
259        self.int().ena().modify(|_, w| {
260            for interrupt in interrupts {
261                match interrupt {
262                    DmaTxInterrupt::TotalEof => w.out_total_eof().bit(enable),
263                    DmaTxInterrupt::DescriptorError => w.out_dscr_err().bit(enable),
264                    DmaTxInterrupt::Eof => w.out_eof().bit(enable),
265                    DmaTxInterrupt::Done => w.out_done().bit(enable),
266                };
267            }
268            w
269        });
270    }
271
272    fn is_listening(&self) -> EnumSet<DmaTxInterrupt> {
273        let mut result = EnumSet::new();
274
275        let int_ena = self.int().ena().read();
276        if int_ena.out_total_eof().bit_is_set() {
277            result |= DmaTxInterrupt::TotalEof;
278        }
279        if int_ena.out_dscr_err().bit_is_set() {
280            result |= DmaTxInterrupt::DescriptorError;
281        }
282        if int_ena.out_eof().bit_is_set() {
283            result |= DmaTxInterrupt::Eof;
284        }
285        if int_ena.out_done().bit_is_set() {
286            result |= DmaTxInterrupt::Done;
287        }
288
289        result
290    }
291
292    fn clear(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
293        self.int().clr().write(|w| {
294            for interrupt in interrupts.into() {
295                match interrupt {
296                    DmaTxInterrupt::TotalEof => w.out_total_eof().clear_bit_by_one(),
297                    DmaTxInterrupt::DescriptorError => w.out_dscr_err().clear_bit_by_one(),
298                    DmaTxInterrupt::Eof => w.out_eof().clear_bit_by_one(),
299                    DmaTxInterrupt::Done => w.out_done().clear_bit_by_one(),
300                };
301            }
302            w
303        });
304    }
305
306    fn pending_interrupts(&self) -> EnumSet<DmaTxInterrupt> {
307        let mut result = EnumSet::new();
308
309        let int_raw = self.int().raw().read();
310        if int_raw.out_total_eof().bit_is_set() {
311            result |= DmaTxInterrupt::TotalEof;
312        }
313        if int_raw.out_dscr_err().bit_is_set() {
314            result |= DmaTxInterrupt::DescriptorError;
315        }
316        if int_raw.out_eof().bit_is_set() {
317            result |= DmaTxInterrupt::Eof;
318        }
319        if int_raw.out_done().bit_is_set() {
320            result |= DmaTxInterrupt::Done;
321        }
322
323        result
324    }
325
326    fn waker(&self) -> &'static AtomicWaker {
327        &TX_WAKERS[self.0 as usize]
328    }
329
330    fn is_async(&self) -> bool {
331        cfg_if::cfg_if! {
332            if #[cfg(any(esp32c2, esp32c3))] {
333                TX_IS_ASYNC[self.0 as usize].load(portable_atomic::Ordering::Acquire)
334            } else {
335                true
336            }
337        }
338    }
339
340    fn set_async(&self, _is_async: bool) {
341        cfg_if::cfg_if! {
342            if #[cfg(any(esp32c2, esp32c3))] {
343                TX_IS_ASYNC[self.0 as usize].store(_is_async, portable_atomic::Ordering::Release);
344            }
345        }
346    }
347}
348
349impl crate::private::Sealed for AnyGdmaRxChannel {}
350impl DmaRxChannel for AnyGdmaRxChannel {}
351
352impl AnyGdmaRxChannel {
353    #[inline(always)]
354    fn ch(&self) -> &pac::dma::ch::CH {
355        DMA::regs().ch(self.0 as usize)
356    }
357
358    #[cfg(any(esp32c2, esp32c3))]
359    #[inline(always)]
360    fn int(&self) -> &pac::dma::int_ch::INT_CH {
361        DMA::regs().int_ch(self.0 as usize)
362    }
363
364    #[inline(always)]
365    #[cfg(any(esp32c6, esp32h2))]
366    fn int(&self) -> &pac::dma::in_int_ch::IN_INT_CH {
367        DMA::regs().in_int_ch(self.0 as usize)
368    }
369
370    #[cfg(esp32s3)]
371    #[inline(always)]
372    fn int(&self) -> &pac::dma::ch::in_int::IN_INT {
373        DMA::regs().ch(self.0 as usize).in_int()
374    }
375}
376
377impl RegisterAccess for AnyGdmaRxChannel {
378    fn reset(&self) {
379        let conf0 = self.ch().in_conf0();
380        conf0.modify(|_, w| w.in_rst().set_bit());
381        conf0.modify(|_, w| w.in_rst().clear_bit());
382    }
383
384    fn set_burst_mode(&self, burst_mode: BurstConfig) {
385        self.ch()
386            .in_conf0()
387            .modify(|_, w| w.in_data_burst_en().bit(burst_mode.is_burst_enabled()));
388    }
389
390    fn set_descr_burst_mode(&self, burst_mode: bool) {
391        self.ch()
392            .in_conf0()
393            .modify(|_, w| w.indscr_burst_en().bit(burst_mode));
394    }
395
396    fn set_priority(&self, priority: DmaPriority) {
397        self.ch()
398            .in_pri()
399            .write(|w| unsafe { w.rx_pri().bits(priority as u8) });
400    }
401
402    fn set_peripheral(&self, peripheral: u8) {
403        self.ch()
404            .in_peri_sel()
405            .modify(|_, w| unsafe { w.peri_in_sel().bits(peripheral) });
406    }
407
408    fn set_link_addr(&self, address: u32) {
409        self.ch()
410            .in_link()
411            .modify(|_, w| unsafe { w.inlink_addr().bits(address) });
412    }
413
414    fn start(&self) {
415        self.ch()
416            .in_link()
417            .modify(|_, w| w.inlink_start().set_bit());
418    }
419
420    fn stop(&self) {
421        self.ch().in_link().modify(|_, w| w.inlink_stop().set_bit());
422    }
423
424    fn restart(&self) {
425        self.ch()
426            .in_link()
427            .modify(|_, w| w.inlink_restart().set_bit());
428    }
429
430    fn set_check_owner(&self, check_owner: Option<bool>) {
431        self.ch()
432            .in_conf1()
433            .modify(|_, w| w.in_check_owner().bit(check_owner.unwrap_or(true)));
434    }
435
436    #[cfg(esp32s3)]
437    fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize) {
438        self.ch()
439            .in_conf1()
440            .modify(|_, w| unsafe { w.in_ext_mem_bk_size().bits(size as u8) });
441    }
442
443    #[cfg(psram_dma)]
444    fn can_access_psram(&self) -> bool {
445        true
446    }
447}
448
449impl RxRegisterAccess for AnyGdmaRxChannel {
450    fn set_mem2mem_mode(&self, value: bool) {
451        self.ch()
452            .in_conf0()
453            .modify(|_, w| w.mem_trans_en().bit(value));
454    }
455
456    fn async_handler(&self) -> Option<InterruptHandler> {
457        match self.0 {
458            0 => DmaChannel0::handler_in(),
459            #[cfg(not(esp32c2))]
460            1 => DmaChannel1::handler_in(),
461            #[cfg(not(esp32c2))]
462            2 => DmaChannel2::handler_in(),
463            #[cfg(esp32s3)]
464            3 => DmaChannel3::handler_in(),
465            #[cfg(esp32s3)]
466            4 => DmaChannel4::handler_in(),
467            _ => unreachable!(),
468        }
469    }
470
471    fn peripheral_interrupt(&self) -> Option<Interrupt> {
472        match self.0 {
473            0 => DmaChannel0::isr_in(),
474            #[cfg(not(esp32c2))]
475            1 => DmaChannel1::isr_in(),
476            #[cfg(not(esp32c2))]
477            2 => DmaChannel2::isr_in(),
478            #[cfg(esp32s3)]
479            3 => DmaChannel3::isr_in(),
480            #[cfg(esp32s3)]
481            4 => DmaChannel4::isr_in(),
482            _ => unreachable!(),
483        }
484    }
485}
486
487impl InterruptAccess<DmaRxInterrupt> for AnyGdmaRxChannel {
488    fn enable_listen(&self, interrupts: EnumSet<DmaRxInterrupt>, enable: bool) {
489        self.int().ena().modify(|_, w| {
490            for interrupt in interrupts {
491                match interrupt {
492                    DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().bit(enable),
493                    DmaRxInterrupt::ErrorEof => w.in_err_eof().bit(enable),
494                    DmaRxInterrupt::DescriptorError => w.in_dscr_err().bit(enable),
495                    DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().bit(enable),
496                    DmaRxInterrupt::Done => w.in_done().bit(enable),
497                };
498            }
499            w
500        });
501    }
502
503    fn is_listening(&self) -> EnumSet<DmaRxInterrupt> {
504        let mut result = EnumSet::new();
505
506        let int_ena = self.int().ena().read();
507        if int_ena.in_dscr_err().bit_is_set() {
508            result |= DmaRxInterrupt::DescriptorError;
509        }
510        if int_ena.in_dscr_empty().bit_is_set() {
511            result |= DmaRxInterrupt::DescriptorEmpty;
512        }
513        if int_ena.in_suc_eof().bit_is_set() {
514            result |= DmaRxInterrupt::SuccessfulEof;
515        }
516        if int_ena.in_err_eof().bit_is_set() {
517            result |= DmaRxInterrupt::ErrorEof;
518        }
519        if int_ena.in_done().bit_is_set() {
520            result |= DmaRxInterrupt::Done;
521        }
522
523        result
524    }
525
526    fn clear(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
527        self.int().clr().write(|w| {
528            for interrupt in interrupts.into() {
529                match interrupt {
530                    DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().clear_bit_by_one(),
531                    DmaRxInterrupt::ErrorEof => w.in_err_eof().clear_bit_by_one(),
532                    DmaRxInterrupt::DescriptorError => w.in_dscr_err().clear_bit_by_one(),
533                    DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().clear_bit_by_one(),
534                    DmaRxInterrupt::Done => w.in_done().clear_bit_by_one(),
535                };
536            }
537            w
538        });
539    }
540
541    fn pending_interrupts(&self) -> EnumSet<DmaRxInterrupt> {
542        let mut result = EnumSet::new();
543
544        let int_raw = self.int().raw().read();
545        if int_raw.in_dscr_err().bit_is_set() {
546            result |= DmaRxInterrupt::DescriptorError;
547        }
548        if int_raw.in_dscr_empty().bit_is_set() {
549            result |= DmaRxInterrupt::DescriptorEmpty;
550        }
551        if int_raw.in_suc_eof().bit_is_set() {
552            result |= DmaRxInterrupt::SuccessfulEof;
553        }
554        if int_raw.in_err_eof().bit_is_set() {
555            result |= DmaRxInterrupt::ErrorEof;
556        }
557        if int_raw.in_done().bit_is_set() {
558            result |= DmaRxInterrupt::Done;
559        }
560
561        result
562    }
563
564    fn waker(&self) -> &'static AtomicWaker {
565        &RX_WAKERS[self.0 as usize]
566    }
567
568    fn is_async(&self) -> bool {
569        cfg_if::cfg_if! {
570            if #[cfg(any(esp32c2, esp32c3))] {
571                RX_IS_ASYNC[self.0 as usize].load(portable_atomic::Ordering::Acquire)
572            } else {
573                true
574            }
575        }
576    }
577
578    fn set_async(&self, _is_async: bool) {
579        cfg_if::cfg_if! {
580            if #[cfg(any(esp32c2, esp32c3))] {
581                RX_IS_ASYNC[self.0 as usize].store(_is_async, portable_atomic::Ordering::Release);
582            }
583        }
584    }
585}
586
587impl<CH: DmaChannel, Dm: DriverMode> Channel<'_, Dm, CH> {
588    /// Asserts that the channel is compatible with the given peripheral.
589    pub fn runtime_ensure_compatible<P: DmaEligible>(&self, _peripheral: &PeripheralRef<'_, P>) {
590        // No runtime checks; GDMA channels are compatible with any peripheral
591    }
592}
593
594macro_rules! impl_channel {
595    ($num:literal, $interrupt_in:ident $(, $interrupt_out:ident)? ) => {
596        paste::paste! {
597            /// A description of a specific GDMA channel
598            #[non_exhaustive]
599            #[derive(Debug, PartialEq, Eq)]
600            #[cfg_attr(feature = "defmt", derive(defmt::Format))]
601            pub struct [<DmaChannel $num>] {}
602
603            impl $crate::private::Sealed for [<DmaChannel $num>] {}
604
605            impl Peripheral for [<DmaChannel $num>] {
606                type P = Self;
607
608                unsafe fn clone_unchecked(&self) -> Self::P {
609                    Self::steal()
610                }
611            }
612
613            impl [<DmaChannel $num>] {
614                /// Unsafely constructs a new DMA channel.
615                ///
616                /// # Safety
617                ///
618                /// The caller must ensure that only a single instance is used.
619                pub unsafe fn steal() -> Self {
620                    Self {}
621                }
622            }
623
624            impl [<DmaChannel $num>] {
625                fn handler_in() -> Option<InterruptHandler> {
626                    $crate::if_set! {
627                        $({
628                            // $interrupt_out is present, meaning we have split handlers
629                            #[handler(priority = Priority::max())]
630                            fn interrupt_handler_in() {
631                                $crate::ignore!($interrupt_out);
632                                super::asynch::handle_in_interrupt::<[< DmaChannel $num >]>();
633                            }
634                            Some(interrupt_handler_in)
635                        })?,
636                        {
637                            #[handler(priority = Priority::max())]
638                            fn interrupt_handler() {
639                                super::asynch::handle_in_interrupt::<[< DmaChannel $num >]>();
640                                super::asynch::handle_out_interrupt::<[< DmaChannel $num >]>();
641                            }
642                            Some(interrupt_handler)
643                        }
644                    }
645                }
646
647                fn isr_in() -> Option<Interrupt> {
648                    Some(Interrupt::$interrupt_in)
649                }
650
651                fn handler_out() -> Option<InterruptHandler> {
652                    $crate::if_set! {
653                        $({
654                            #[handler(priority = Priority::max())]
655                            fn interrupt_handler_out() {
656                                $crate::ignore!($interrupt_out);
657                                super::asynch::handle_out_interrupt::<[< DmaChannel $num >]>();
658                            }
659                            Some(interrupt_handler_out)
660                        })?,
661                        None
662                    }
663                }
664
665                fn isr_out() -> Option<Interrupt> {
666                    $crate::if_set! { $(Some(Interrupt::$interrupt_out))?, None }
667                }
668            }
669
670            impl DmaChannel for [<DmaChannel $num>] {
671                type Rx = AnyGdmaRxChannel;
672                type Tx = AnyGdmaTxChannel;
673
674                unsafe fn split_internal(self, _: $crate::private::Internal) -> (Self::Rx, Self::Tx) {
675                    (AnyGdmaRxChannel($num), AnyGdmaTxChannel($num))
676                }
677            }
678
679            impl DmaChannelConvert<AnyGdmaChannel> for [<DmaChannel $num>] {
680                fn degrade(self) -> AnyGdmaChannel {
681                    AnyGdmaChannel($num)
682                }
683            }
684
685            impl DmaChannelConvert<AnyGdmaRxChannel> for [<DmaChannel $num>] {
686                fn degrade(self) -> AnyGdmaRxChannel {
687                    AnyGdmaRxChannel($num)
688                }
689            }
690
691            impl DmaChannelConvert<AnyGdmaTxChannel> for [<DmaChannel $num>] {
692                fn degrade(self) -> AnyGdmaTxChannel {
693                    AnyGdmaTxChannel($num)
694                }
695            }
696
697            impl DmaChannelExt for [<DmaChannel $num>] {
698                fn rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt> {
699                    AnyGdmaRxChannel($num)
700                }
701
702                fn tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
703                    AnyGdmaTxChannel($num)
704                }
705            }
706        }
707    };
708}
709
710cfg_if::cfg_if! {
711    if #[cfg(esp32c2)] {
712        const CHANNEL_COUNT: usize = 1;
713        impl_channel!(0, DMA_CH0);
714    } else if #[cfg(esp32c3)] {
715        const CHANNEL_COUNT: usize = 3;
716        impl_channel!(0, DMA_CH0);
717        impl_channel!(1, DMA_CH1);
718        impl_channel!(2, DMA_CH2);
719    } else if #[cfg(any(esp32c6, esp32h2))] {
720        const CHANNEL_COUNT: usize = 3;
721        impl_channel!(0, DMA_IN_CH0, DMA_OUT_CH0);
722        impl_channel!(1, DMA_IN_CH1, DMA_OUT_CH1);
723        impl_channel!(2, DMA_IN_CH2, DMA_OUT_CH2);
724    } else if #[cfg(esp32s3)] {
725        const CHANNEL_COUNT: usize = 5;
726        impl_channel!(0, DMA_IN_CH0, DMA_OUT_CH0);
727        impl_channel!(1, DMA_IN_CH1, DMA_OUT_CH1);
728        impl_channel!(2, DMA_IN_CH2, DMA_OUT_CH2);
729        impl_channel!(3, DMA_IN_CH3, DMA_OUT_CH3);
730        impl_channel!(4, DMA_IN_CH4, DMA_OUT_CH4);
731    }
732}
733
734crate::dma::impl_dma_eligible! {
735    AnyGdmaChannel {
736        #[cfg(spi2)]
737        SPI2 => Spi2,
738
739        #[cfg(spi3)]
740        SPI3 => Spi3,
741
742        #[cfg(uhci0)]
743        UHCI0 => Uhci0,
744
745        #[cfg(i2s0)]
746        I2S0 => I2s0,
747
748        #[cfg(i2s1)]
749        I2S1 => I2s1,
750
751        #[cfg(esp32s3)]
752        LCD_CAM => LcdCam,
753
754        #[cfg(all(gdma, aes))]
755        AES => Aes,
756
757        #[cfg(all(gdma, sha))]
758        SHA => Sha,
759
760        #[cfg(any(esp32c3, esp32c6, esp32h2, esp32s3))]
761        ADC1 => Adc,
762
763        #[cfg(any(esp32c3, esp32s3))]
764        ADC2 => Adc,
765
766        #[cfg(esp32s3)]
767        RMT => Rmt,
768
769        #[cfg(parl_io)]
770        PARL_IO => ParlIo,
771
772        #[cfg(any(esp32c2, esp32c6, esp32h2))]
773        MEM2MEM1 => Mem2Mem1,
774    }
775}
776
777#[cfg(any(esp32c6, esp32h2))]
778crate::dma::impl_dma_eligible! {
779    AnyGdmaChannel {
780        MEM2MEM4 => Mem2Mem4,
781        MEM2MEM5 => Mem2Mem5,
782        MEM2MEM10 => Mem2Mem10,
783        MEM2MEM11 => Mem2Mem11,
784        MEM2MEM12 => Mem2Mem12,
785        MEM2MEM13 => Mem2Mem13,
786        MEM2MEM14 => Mem2Mem14,
787        MEM2MEM15 => Mem2Mem15,
788    }
789}
790
791pub(super) fn init_dma(_cs: CriticalSection<'_>) {
792    DMA::regs()
793        .misc_conf()
794        .modify(|_, w| w.ahbm_rst_inter().set_bit());
795    DMA::regs()
796        .misc_conf()
797        .modify(|_, w| w.ahbm_rst_inter().clear_bit());
798    DMA::regs().misc_conf().modify(|_, w| w.clk_en().set_bit());
799}