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