1use enumset::EnumSet;
2use portable_atomic::{AtomicBool, Ordering};
3
4use crate::{
5 asynch::AtomicWaker,
6 dma::{
7 BurstConfig,
8 DmaChannel,
9 DmaChannelConvert,
10 DmaChannelExt,
11 DmaExtMemBKSize,
12 DmaPeripheral,
13 DmaRxChannel,
14 DmaRxInterrupt,
15 DmaTxChannel,
16 DmaTxInterrupt,
17 InterruptAccess,
18 PdmaChannel,
19 RegisterAccess,
20 RxRegisterAccess,
21 TxRegisterAccess,
22 asynch,
23 },
24 interrupt::{InterruptHandler, Priority},
25 peripherals::{DMA_COPY, Interrupt},
26};
27
28pub(super) type CopyRegisterBlock = crate::pac::copy_dma::RegisterBlock;
29
30#[derive(Debug)]
32#[cfg_attr(feature = "defmt", derive(defmt::Format))]
33pub struct CopyDmaRxChannel<'d>(pub(crate) DMA_COPY<'d>);
34
35impl CopyDmaRxChannel<'_> {
36 fn regs(&self) -> &CopyRegisterBlock {
37 self.0.register_block()
38 }
39}
40
41impl crate::private::Sealed for CopyDmaRxChannel<'_> {}
42impl DmaRxChannel for CopyDmaRxChannel<'_> {}
43
44#[derive(Debug)]
46#[cfg_attr(feature = "defmt", derive(defmt::Format))]
47pub struct CopyDmaTxChannel<'d>(pub(crate) DMA_COPY<'d>);
48
49impl CopyDmaTxChannel<'_> {
50 fn regs(&self) -> &CopyRegisterBlock {
51 self.0.register_block()
52 }
53}
54
55impl crate::private::Sealed for CopyDmaTxChannel<'_> {}
56impl DmaTxChannel for CopyDmaTxChannel<'_> {}
57
58impl RegisterAccess for CopyDmaTxChannel<'_> {
59 fn reset(&self) {
60 self.regs().conf().modify(|_, w| w.out_rst().set_bit());
61 self.regs().conf().modify(|_, w| w.out_rst().clear_bit());
62 }
63
64 fn set_burst_mode(&self, _burst_mode: BurstConfig) {}
65
66 fn set_descr_burst_mode(&self, _burst_mode: bool) {}
67
68 fn set_peripheral(&self, _peripheral: u8) {
69 }
71
72 fn set_link_addr(&self, address: u32) {
73 self.regs()
74 .out_link()
75 .modify(|_, w| unsafe { w.outlink_addr().bits(address) });
76 }
77
78 fn start(&self) {
79 self.regs()
80 .out_link()
81 .modify(|_, w| w.outlink_start().set_bit());
82 }
83
84 fn stop(&self) {
85 self.regs()
86 .out_link()
87 .modify(|_, w| w.outlink_stop().set_bit());
88 }
89
90 fn restart(&self) {
91 self.regs()
92 .out_link()
93 .modify(|_, w| w.outlink_restart().set_bit());
94 }
95
96 fn set_check_owner(&self, check_owner: Option<bool>) {
97 if check_owner == Some(true) {
98 panic!("Copy DMA does not support checking descriptor ownership");
99 }
100 }
101
102 fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool {
103 self.0.is_compatible_with(peripheral)
104 }
105
106 #[cfg(psram_dma)]
107 fn set_ext_mem_block_size(&self, _size: DmaExtMemBKSize) {
108 }
110
111 #[cfg(psram_dma)]
112 fn can_access_psram(&self) -> bool {
113 false
114 }
115}
116
117impl TxRegisterAccess for CopyDmaTxChannel<'_> {
118 fn is_fifo_empty(&self) -> bool {
119 self.regs().in_st().read().fifo_empty().bit()
120 }
121
122 fn set_auto_write_back(&self, enable: bool) {
123 self.regs()
124 .conf()
125 .modify(|_, w| w.out_auto_wrback().bit(enable));
126 }
127
128 fn last_dscr_address(&self) -> usize {
129 self.regs()
130 .out_eof_des_addr()
131 .read()
132 .out_eof_des_addr()
133 .bits() as usize
134 }
135
136 fn peripheral_interrupt(&self) -> Option<Interrupt> {
137 None
138 }
139
140 fn async_handler(&self) -> Option<InterruptHandler> {
141 None
142 }
143}
144
145impl InterruptAccess<DmaTxInterrupt> for CopyDmaTxChannel<'_> {
146 fn enable_listen(&self, interrupts: EnumSet<DmaTxInterrupt>, enable: bool) {
147 self.regs().int_ena().modify(|_, w| {
148 for interrupt in interrupts {
149 match interrupt {
150 DmaTxInterrupt::TotalEof => w.out_total_eof().bit(enable),
151 DmaTxInterrupt::DescriptorError => w.out_dscr_err().bit(enable),
152 DmaTxInterrupt::Eof => w.out_eof().bit(enable),
153 DmaTxInterrupt::Done => w.out_done().bit(enable),
154 };
155 }
156 w
157 });
158 }
159
160 fn is_listening(&self) -> EnumSet<DmaTxInterrupt> {
161 let mut result = EnumSet::new();
162
163 let int_ena = self.regs().int_ena().read();
164 if int_ena.out_total_eof().bit_is_set() {
165 result |= DmaTxInterrupt::TotalEof;
166 }
167 if int_ena.out_dscr_err().bit_is_set() {
168 result |= DmaTxInterrupt::DescriptorError;
169 }
170 if int_ena.out_eof().bit_is_set() {
171 result |= DmaTxInterrupt::Eof;
172 }
173 if int_ena.out_done().bit_is_set() {
174 result |= DmaTxInterrupt::Done;
175 }
176
177 result
178 }
179
180 fn clear(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
181 self.regs().int_clr().write(|w| {
182 for interrupt in interrupts.into() {
183 match interrupt {
184 DmaTxInterrupt::TotalEof => w.out_total_eof().clear_bit_by_one(),
185 DmaTxInterrupt::DescriptorError => w.out_dscr_err().clear_bit_by_one(),
186 DmaTxInterrupt::Eof => w.out_eof().clear_bit_by_one(),
187 DmaTxInterrupt::Done => w.out_done().clear_bit_by_one(),
188 };
189 }
190 w
191 });
192 }
193
194 fn pending_interrupts(&self) -> EnumSet<DmaTxInterrupt> {
195 let mut result = EnumSet::new();
196
197 let int_raw = self.regs().int_raw().read();
198 if int_raw.out_total_eof().bit_is_set() {
199 result |= DmaTxInterrupt::TotalEof;
200 }
201 if int_raw.out_dscr_err().bit_is_set() {
202 result |= DmaTxInterrupt::DescriptorError;
203 }
204 if int_raw.out_eof().bit_is_set() {
205 result |= DmaTxInterrupt::Eof;
206 }
207 if int_raw.out_done().bit_is_set() {
208 result |= DmaTxInterrupt::Done;
209 }
210
211 result
212 }
213
214 fn waker(&self) -> &'static AtomicWaker {
215 self.0.tx_waker()
216 }
217
218 fn is_async(&self) -> bool {
219 self.0.tx_async_flag().load(Ordering::Acquire)
220 }
221
222 fn set_async(&self, is_async: bool) {
223 self.0.tx_async_flag().store(is_async, Ordering::Release);
224 }
225}
226
227impl RegisterAccess for CopyDmaRxChannel<'_> {
228 fn reset(&self) {
229 self.regs().conf().modify(|_, w| w.in_rst().set_bit());
230 self.regs().conf().modify(|_, w| w.in_rst().clear_bit());
231 }
232
233 fn set_burst_mode(&self, _burst_mode: BurstConfig) {}
234
235 fn set_descr_burst_mode(&self, _burst_mode: bool) {}
236
237 fn set_peripheral(&self, _peripheral: u8) {
238 }
240
241 fn set_link_addr(&self, address: u32) {
242 self.regs()
243 .in_link()
244 .modify(|_, w| unsafe { w.inlink_addr().bits(address) });
245 }
246
247 fn start(&self) {
248 self.regs()
249 .in_link()
250 .modify(|_, w| w.inlink_start().set_bit());
251 }
252
253 fn stop(&self) {
254 self.regs()
255 .in_link()
256 .modify(|_, w| w.inlink_stop().set_bit());
257 }
258
259 fn restart(&self) {
260 self.regs()
261 .in_link()
262 .modify(|_, w| w.inlink_restart().set_bit());
263 }
264
265 fn set_check_owner(&self, check_owner: Option<bool>) {
266 if check_owner == Some(true) {
267 panic!("Copy DMA does not support checking descriptor ownership");
268 }
269 }
270
271 fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool {
272 self.0.is_compatible_with(peripheral)
273 }
274
275 #[cfg(psram_dma)]
276 fn set_ext_mem_block_size(&self, _size: DmaExtMemBKSize) {
277 }
279
280 #[cfg(psram_dma)]
281 fn can_access_psram(&self) -> bool {
282 false
283 }
284}
285
286impl RxRegisterAccess for CopyDmaRxChannel<'_> {
287 fn peripheral_interrupt(&self) -> Option<Interrupt> {
288 None
289 }
290
291 fn async_handler(&self) -> Option<InterruptHandler> {
292 None
293 }
294}
295
296impl InterruptAccess<DmaRxInterrupt> for CopyDmaRxChannel<'_> {
297 fn enable_listen(&self, interrupts: EnumSet<DmaRxInterrupt>, enable: bool) {
298 self.regs().int_ena().modify(|_, w| {
299 for interrupt in interrupts {
300 match interrupt {
301 DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().bit(enable),
302 DmaRxInterrupt::ErrorEof => unimplemented!(),
303 DmaRxInterrupt::DescriptorError => w.in_dscr_err().bit(enable),
304 DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().bit(enable),
305 DmaRxInterrupt::Done => w.in_done().bit(enable),
306 };
307 }
308 w
309 });
310 }
311
312 fn is_listening(&self) -> EnumSet<DmaRxInterrupt> {
313 let mut result = EnumSet::new();
314
315 let int_ena = self.regs().int_ena().read();
316 if int_ena.in_dscr_err().bit_is_set() {
317 result |= DmaRxInterrupt::DescriptorError;
318 }
319 if int_ena.in_dscr_err().bit_is_set() {
320 result |= DmaRxInterrupt::DescriptorEmpty;
321 }
322 if int_ena.in_suc_eof().bit_is_set() {
323 result |= DmaRxInterrupt::SuccessfulEof;
324 }
325 if int_ena.in_done().bit_is_set() {
326 result |= DmaRxInterrupt::Done;
327 }
328
329 result
330 }
331
332 fn clear(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
333 self.regs().int_clr().write(|w| {
334 for interrupt in interrupts.into() {
335 match interrupt {
336 DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().clear_bit_by_one(),
337 DmaRxInterrupt::ErrorEof => continue,
338 DmaRxInterrupt::DescriptorError => w.in_dscr_err().clear_bit_by_one(),
339 DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().clear_bit_by_one(),
340 DmaRxInterrupt::Done => w.in_done().clear_bit_by_one(),
341 };
342 }
343 w
344 });
345 }
346
347 fn pending_interrupts(&self) -> EnumSet<DmaRxInterrupt> {
348 let mut result = EnumSet::new();
349
350 let int_raw = self.regs().int_raw().read();
351 if int_raw.in_dscr_err().bit_is_set() {
352 result |= DmaRxInterrupt::DescriptorError;
353 }
354 if int_raw.in_dscr_empty().bit_is_set() {
355 result |= DmaRxInterrupt::DescriptorEmpty;
356 }
357 if int_raw.in_suc_eof().bit_is_set() {
358 result |= DmaRxInterrupt::SuccessfulEof;
359 }
360 if int_raw.in_done().bit_is_set() {
361 result |= DmaRxInterrupt::Done;
362 }
363
364 result
365 }
366
367 fn waker(&self) -> &'static AtomicWaker {
368 self.0.rx_waker()
369 }
370
371 fn is_async(&self) -> bool {
372 self.0.rx_async_flag().load(Ordering::Relaxed)
373 }
374
375 fn set_async(&self, _is_async: bool) {
376 self.0.rx_async_flag().store(_is_async, Ordering::Relaxed);
377 }
378}
379
380impl<'d> DmaChannel for DMA_COPY<'d> {
381 type Rx = CopyDmaRxChannel<'d>;
382 type Tx = CopyDmaTxChannel<'d>;
383 unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx) {
384 (
385 CopyDmaRxChannel(unsafe { Self::steal() }),
386 CopyDmaTxChannel(unsafe { Self::steal() }),
387 )
388 }
389}
390impl DmaChannelExt for DMA_COPY<'_> {
391 fn rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt> {
392 CopyDmaRxChannel(unsafe { Self::steal() })
393 }
394 fn tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
395 CopyDmaTxChannel(unsafe { Self::steal() })
396 }
397}
398impl PdmaChannel for DMA_COPY<'_> {
399 type RegisterBlock = CopyRegisterBlock;
400 fn register_block(&self) -> &Self::RegisterBlock {
401 DMA_COPY::regs()
402 }
403 fn tx_waker(&self) -> &'static AtomicWaker {
404 static WAKER: AtomicWaker = AtomicWaker::new();
405 &WAKER
406 }
407 fn rx_waker(&self) -> &'static AtomicWaker {
408 static WAKER: AtomicWaker = AtomicWaker::new();
409 &WAKER
410 }
411 fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool {
412 let compatible_peripherals = [DmaPeripheral::Aes, DmaPeripheral::Sha];
413 compatible_peripherals.contains(&peripheral)
414 }
415 fn peripheral_interrupt(&self) -> Interrupt {
416 Interrupt::DMA_COPY
417 }
418 fn async_handler(&self) -> InterruptHandler {
419 pub(crate) extern "C" fn __esp_hal_internal_interrupt_handler() {
420 asynch::handle_in_interrupt::<DMA_COPY<'static>>();
421 asynch::handle_out_interrupt::<DMA_COPY<'static>>();
422 }
423 #[allow(non_upper_case_globals)]
424 pub(crate) static interrupt_handler: InterruptHandler =
425 InterruptHandler::new(__esp_hal_internal_interrupt_handler, Priority::max());
426 interrupt_handler
427 }
428 fn rx_async_flag(&self) -> &'static AtomicBool {
429 static FLAG: AtomicBool = AtomicBool::new(false);
430 &FLAG
431 }
432 fn tx_async_flag(&self) -> &'static AtomicBool {
433 static FLAG: AtomicBool = AtomicBool::new(false);
434 &FLAG
435 }
436}
437impl<'d> DmaChannelConvert<CopyDmaRxChannel<'d>> for DMA_COPY<'d> {
438 fn degrade(self) -> CopyDmaRxChannel<'d> {
439 CopyDmaRxChannel(self)
440 }
441}
442impl<'d> DmaChannelConvert<CopyDmaTxChannel<'d>> for DMA_COPY<'d> {
443 fn degrade(self) -> CopyDmaTxChannel<'d> {
444 CopyDmaTxChannel(self)
445 }
446}