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