1use critical_section::CriticalSection;
15use portable_atomic::AtomicBool;
16
17use crate::{asynch::AtomicWaker, dma::*, handler, interrupt::Priority, peripherals::Interrupt};
18
19#[cfg(esp32s2)]
20mod copy;
21#[cfg(esp32s2)]
22mod crypto;
23mod i2s;
24mod spi;
25
26#[cfg(esp32s2)]
27pub use copy::*;
28#[cfg(esp32s2)]
29pub use crypto::*;
30pub use i2s::*;
31pub use spi::*;
32
33#[doc(hidden)]
34pub trait PdmaChannel: crate::private::Sealed {
35 type RegisterBlock;
36
37 fn register_block(&self) -> &Self::RegisterBlock;
38 fn tx_waker(&self) -> &'static AtomicWaker;
39 fn rx_waker(&self) -> &'static AtomicWaker;
40 fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool;
41
42 fn peripheral_interrupt(&self) -> Interrupt;
43 fn async_handler(&self) -> InterruptHandler;
44 fn rx_async_flag(&self) -> &'static AtomicBool;
45 fn tx_async_flag(&self) -> &'static AtomicBool;
46}
47
48macro_rules! impl_pdma_channel {
49 ($peri:ident, $register_block:ident, $instance:ident, $int:ident, [$($compatible:ident),*]) => {
50 paste::paste! {
51 use $crate::peripherals::[< $instance >];
52 impl<'d> DmaChannel for $instance<'d> {
53 type Rx = [<$peri DmaRxChannel>]<'d>;
54 type Tx = [<$peri DmaTxChannel>]<'d>;
55
56 unsafe fn split_internal(self, _: $crate::private::Internal) -> (Self::Rx, Self::Tx) { unsafe {
57 (
58 [<$peri DmaRxChannel>](Self::steal().into()),
59 [<$peri DmaTxChannel>](Self::steal().into()),
60 )
61 }}
62 }
63
64 impl DmaChannelExt for $instance<'_> {
65 fn rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt> {
66 [<$peri DmaRxChannel>](unsafe { Self::steal() }.into())
67 }
68 fn tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
69 [<$peri DmaTxChannel>](unsafe { Self::steal() }.into())
70 }
71 }
72
73 impl PdmaChannel for $instance<'_> {
74 type RegisterBlock = $register_block;
75
76 fn register_block(&self) -> &Self::RegisterBlock {
77 $crate::peripherals::[< $instance >]::regs()
78 }
79 fn tx_waker(&self) -> &'static AtomicWaker {
80 static WAKER: AtomicWaker = AtomicWaker::new();
81 &WAKER
82 }
83 fn rx_waker(&self) -> &'static AtomicWaker {
84 static WAKER: AtomicWaker = AtomicWaker::new();
85 &WAKER
86 }
87 fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool {
88 let compatible_peripherals = [$(DmaPeripheral::$compatible),*];
89 compatible_peripherals.contains(&peripheral)
90 }
91
92 fn peripheral_interrupt(&self) -> Interrupt {
93 Interrupt::$int
94 }
95
96 fn async_handler(&self) -> InterruptHandler {
97 #[handler(priority = Priority::max())]
98 pub(crate) fn interrupt_handler() {
99 super::asynch::handle_in_interrupt::<$instance<'static>>();
100 super::asynch::handle_out_interrupt::<$instance<'static>>();
101 }
102
103 interrupt_handler
104 }
105 fn rx_async_flag(&self) -> &'static AtomicBool {
106 static FLAG: AtomicBool = AtomicBool::new(false);
107 &FLAG
108 }
109 fn tx_async_flag(&self) -> &'static AtomicBool {
110 static FLAG: AtomicBool = AtomicBool::new(false);
111 &FLAG
112 }
113 }
114
115 impl<'d> DmaChannelConvert<[<$peri DmaChannel>]<'d>> for $instance<'d> {
116 fn degrade(self) -> [<$peri DmaChannel>]<'d> {
117 self.into()
118 }
119 }
120
121 impl<'d> DmaChannelConvert<[<$peri DmaRxChannel>]<'d>> for $instance<'d> {
122 fn degrade(self) -> [<$peri DmaRxChannel>]<'d> {
123 [<$peri DmaRxChannel>](self.into())
124 }
125 }
126
127 impl<'d> DmaChannelConvert<[<$peri DmaTxChannel>]<'d>> for $instance<'d> {
128 fn degrade(self) -> [<$peri DmaTxChannel>]<'d> {
129 [<$peri DmaTxChannel>](self.into())
130 }
131 }
132 }
133 };
134}
135
136impl_pdma_channel!(AnySpi, SpiRegisterBlock, DMA_SPI2, SPI2_DMA, [Spi2]);
137impl_pdma_channel!(AnySpi, SpiRegisterBlock, DMA_SPI3, SPI3_DMA, [Spi3]);
138
139impl_pdma_channel!(AnyI2s, I2sRegisterBlock, DMA_I2S0, I2S0, [I2s0]);
140#[cfg(i2s1)]
141impl_pdma_channel!(AnyI2s, I2sRegisterBlock, DMA_I2S1, I2S1, [I2s1]);
142
143crate::dma::impl_dma_eligible!([DMA_SPI2] SPI2 => Spi2);
147crate::dma::impl_dma_eligible!([DMA_SPI3] SPI3 => Spi3);
148crate::dma::impl_dma_eligible!([DMA_I2S0] I2S0 => I2s0);
149#[cfg(i2s1)]
150crate::dma::impl_dma_eligible!([DMA_I2S1] I2S1 => I2s1);
151#[cfg(esp32s2)]
152use crate::peripherals::DMA_CRYPTO;
153#[cfg(esp32s2)]
154crate::dma::impl_dma_eligible!([DMA_CRYPTO] AES => Aes);
155#[cfg(esp32s2)]
156crate::dma::impl_dma_eligible!([DMA_CRYPTO] SHA => Sha);
157
158pub(super) fn init_dma(_cs: CriticalSection<'_>) {
159 #[cfg(esp32)]
160 {
161 use crate::peripherals::DPORT;
167
168 DPORT::regs()
169 .spi_dma_chan_sel()
170 .modify(|_, w| unsafe { w.spi2_dma_chan_sel().bits(1).spi3_dma_chan_sel().bits(2) });
171 }
172
173 #[cfg(esp32s2)]
174 {
175 use crate::peripherals::DMA_COPY;
181
182 DMA_COPY::regs().conf().modify(|_, w| w.clk_en().set_bit());
183 }
184}
185
186impl<CH, Dm> Channel<Dm, CH>
187where
188 CH: DmaChannel,
189 Dm: DriverMode,
190{
191 #[instability::unstable]
193 pub fn runtime_ensure_compatible(&self, peripheral: &impl DmaEligible) {
194 assert!(
195 self.tx
196 .tx_impl
197 .is_compatible_with(peripheral.dma_peripheral()),
198 "This DMA channel is not compatible with {:?}",
199 peripheral.dma_peripheral()
200 );
201 }
202}