esp_hal/dma/pdma/
copy.rs

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