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