esp_hal/dma/engine/
mod.rs1use enumset::{EnumSet, EnumSetType};
2
3use crate::{
4 asynch::AtomicWaker,
5 dma::{BurstConfig, DmaRxInterrupt, DmaTxInterrupt},
6 interrupt::InterruptHandler,
7 peripherals::Interrupt,
8 private::{Internal, Sealed},
9 system::PeripheralGuard,
10};
11
12for_each_dma_engine! {
13 ("AHB_GDMA") => {
14 mod gdma;
15 pub use gdma::*;
16 };
17 ("AXI_GDMA") => {
18 mod axi_gdma;
19 pub use axi_gdma::*;
20 };
21 ("COPY_DMA") => {
22 mod copy;
23 pub use copy::*;
24 };
25 ("CRYPTO_DMA") => {
26 mod crypto;
27 pub use crypto::*;
28 };
29 ("I2S_DMA") => {
30 mod i2s;
31 pub use i2s::*;
32 };
33 ("SPI_DMA") => {
34 mod spi;
35 pub use spi::*;
36 };
37}
38
39pub trait DmaEligiblePeripheral<D: DmaChannel> {
41 fn dma_peripheral(&self) -> DmaPeripheral;
43}
44
45for_each_peripheral! {
46 (dma_eligible $(( $peri:ident, $name:ident, $id:literal, $any_ch:ident )),*) => {
47 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
49 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
50 #[doc(hidden)]
51 pub struct DmaPeripheral(pub(crate) u8);
52 impl DmaPeripheral {
53 $(
54 #[doc = concat!("DMA accesses ", stringify!($name))]
55 pub const $peri: Self = Self($id);
56 )*
57 }
58
59 $(
60 impl<'d> DmaEligiblePeripheral<$any_ch<'d>> for crate::peripherals::$peri<'d> {
61 fn dma_peripheral(&self) -> DmaPeripheral {
62 DmaPeripheral::$peri
63 }
64 }
65 )*
66 };
67}
68
69#[doc(hidden)]
70pub trait RegisterAccess: Sealed {
71 #[allow(private_interfaces)]
72 fn enable(&self) -> Option<PeripheralGuard>;
73
74 fn reset(&self);
76
77 fn set_burst_mode(&self, burst_mode: BurstConfig);
80
81 fn set_descr_burst_mode(&self, burst_mode: bool);
84
85 #[cfg(dma_max_priority_is_set)]
88 fn set_priority(&self, priority: crate::dma::DmaPriority);
89
90 fn set_peripheral(&self, _peripheral: u8) {}
92
93 fn set_link_addr(&self, address: u32);
95
96 fn start(&self);
98
99 fn stop(&self);
101
102 fn restart(&self);
104
105 fn set_check_owner(&self, check_owner: Option<bool>);
108
109 #[cfg(dma_ext_mem_configurable_block_size)]
110 fn set_ext_mem_block_size(&self, size: crate::dma::DmaExtMemBKSize);
111
112 #[cfg(dma_can_access_psram)]
113 fn can_access_psram(&self) -> bool;
114
115 fn compatible_peripherals(&self) -> &[u8];
116
117 fn runtime_ensure_compatible(&self, peripheral: DmaPeripheral) {
118 let peripherals = self.compatible_peripherals();
119 assert!(
120 peripherals.contains(&peripheral.0),
121 "This DMA channel is not compatible with peripheral id {}",
122 peripheral.0
123 );
124 }
125}
126
127#[doc(hidden)]
128pub trait RxRegisterAccess: RegisterAccess {
129 #[cfg(dma_supports_mem2mem)]
130 fn set_mem2mem_mode(&self, value: bool);
131
132 fn peripheral_interrupt(&self) -> Option<Interrupt>;
133 fn async_handler(&self) -> Option<InterruptHandler>;
134}
135
136#[doc(hidden)]
137pub trait TxRegisterAccess: RegisterAccess {
138 fn is_fifo_empty(&self) -> bool;
140
141 fn set_auto_write_back(&self, enable: bool);
143
144 fn last_dscr_address(&self) -> usize;
146
147 fn peripheral_interrupt(&self) -> Option<Interrupt>;
148 fn async_handler(&self) -> Option<InterruptHandler>;
149}
150
151#[doc(hidden)]
152pub trait InterruptAccess<T: EnumSetType>: Sealed {
153 fn listen(&self, interrupts: impl Into<EnumSet<T>>) {
154 self.enable_listen(interrupts.into(), true)
155 }
156 fn unlisten(&self, interrupts: impl Into<EnumSet<T>>) {
157 self.enable_listen(interrupts.into(), false)
158 }
159
160 fn clear_all(&self) {
161 self.clear(EnumSet::all());
162 }
163
164 fn enable_listen(&self, interrupts: EnumSet<T>, enable: bool);
165 fn is_listening(&self) -> EnumSet<T>;
166 fn clear(&self, interrupts: impl Into<EnumSet<T>>);
167 fn pending_interrupts(&self) -> EnumSet<T>;
168 fn waker(&self) -> &'static AtomicWaker;
169
170 fn is_async(&self) -> bool;
171 fn set_async(&self, is_async: bool);
172}
173
174#[instability::unstable]
175pub trait DmaRxChannel: RxRegisterAccess + InterruptAccess<DmaRxInterrupt> {}
176
177#[instability::unstable]
178pub trait DmaTxChannel: TxRegisterAccess + InterruptAccess<DmaTxInterrupt> {}
179
180pub trait DmaChannel: Sized + crate::private::Sealed {
182 type Rx: DmaRxChannel + From<Self>;
184
185 type Tx: DmaTxChannel + From<Self>;
187
188 #[cfg(any(esp32c5, esp32c6, esp32h2, esp32s3))] fn split(self) -> (Self::Rx, Self::Tx) {
191 unsafe { self.split_internal(Internal) }
195 }
196
197 unsafe fn split_internal(self, _: Internal) -> (Self::Rx, Self::Tx);
204}
205
206#[doc(hidden)]
207pub trait DmaChannelExt: DmaChannel {
208 fn rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt>;
209 fn tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt>;
210}
211
212macro_rules! impl_channel_common {
213 ($peri:ident, $instance:ident) => {
214 paste::paste! {
215 impl<'d> DmaChannel for $instance<'d> {
216 type Rx = [<$peri RxChannel>]<'d>;
217 type Tx = [<$peri TxChannel>]<'d>;
218
219 unsafe fn split_internal(self, _: $crate::private::Internal) -> (Self::Rx, Self::Tx) {
220 unsafe {
221 (
222 [<$peri RxChannel>](Self::steal().into()),
223 [<$peri TxChannel>](Self::steal().into()),
224 )
225 }
226 }
227 }
228
229 impl<'d> From<$instance<'d>> for [<$peri RxChannel>]<'d> {
231 fn from(this: $instance<'d>) -> [<$peri RxChannel>]<'d> {
232 [<$peri RxChannel>](this.into())
233 }
234 }
235
236 impl<'d> From<$instance<'d>> for [<$peri TxChannel>]<'d> {
237 fn from(this: $instance<'d>) -> [<$peri TxChannel>]<'d> {
238 [<$peri TxChannel>](this.into())
239 }
240 }
241
242 impl crate::dma::DmaChannelExt for $instance<'_> {
243 fn rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt> {
244 [<$peri RxChannel>]::from(unsafe { Self::steal() })
245 }
246
247 fn tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
248 [<$peri TxChannel>]::from(unsafe { Self::steal() })
249 }
250 }
251 }
252 };
253}
254pub(crate) use impl_channel_common;