esp_hal/dma/pdma/
copy.rs

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/// The RX half of a Copy DMA channel.
31#[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/// The TX half of a Copy DMA channel.
45#[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        // no-op
70    }
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        // not supported
109    }
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        // no-op
239    }
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        // not supported
278    }
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}