Skip to main content

esp_hal/dma/pdma/
copy.rs

1use enumset::EnumSet;
2use portable_atomic::{AtomicBool, Ordering};
3
4use crate::{
5    RegisterToggle,
6    asynch::AtomicWaker,
7    dma::{
8        BurstConfig,
9        DmaChannel,
10        DmaChannelConvert,
11        DmaChannelExt,
12        DmaExtMemBKSize,
13        DmaPeripheral,
14        DmaRxChannel,
15        DmaRxInterrupt,
16        DmaTxChannel,
17        DmaTxInterrupt,
18        InterruptAccess,
19        PdmaChannel,
20        RegisterAccess,
21        RxRegisterAccess,
22        TxRegisterAccess,
23        asynch,
24    },
25    interrupt::{InterruptHandler, Priority},
26    peripherals::{DMA_COPY, Interrupt},
27    system::Peripheral,
28};
29
30pub(super) type CopyRegisterBlock = crate::pac::copy_dma::RegisterBlock;
31
32/// The RX half of a Copy DMA channel.
33#[derive(Debug)]
34#[cfg_attr(feature = "defmt", derive(defmt::Format))]
35pub struct CopyDmaRxChannel<'d>(pub(crate) DMA_COPY<'d>);
36
37impl CopyDmaRxChannel<'_> {
38    fn regs(&self) -> &CopyRegisterBlock {
39        self.0.register_block()
40    }
41}
42
43impl crate::private::Sealed for CopyDmaRxChannel<'_> {}
44impl DmaRxChannel for CopyDmaRxChannel<'_> {}
45
46/// The TX half of a Copy DMA channel.
47#[derive(Debug)]
48#[cfg_attr(feature = "defmt", derive(defmt::Format))]
49pub struct CopyDmaTxChannel<'d>(pub(crate) DMA_COPY<'d>);
50
51impl CopyDmaTxChannel<'_> {
52    fn regs(&self) -> &CopyRegisterBlock {
53        self.0.register_block()
54    }
55}
56
57impl crate::private::Sealed for CopyDmaTxChannel<'_> {}
58impl DmaTxChannel for CopyDmaTxChannel<'_> {}
59
60impl RegisterAccess for CopyDmaTxChannel<'_> {
61    fn peripheral_clock(&self) -> Option<Peripheral> {
62        Some(Peripheral::CopyDma)
63    }
64
65    fn reset(&self) {
66        self.regs().conf().toggle(|w, bit| w.out_rst().bit(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(dma_ext_mem_configurable_block_size)]
112    fn set_ext_mem_block_size(&self, _size: DmaExtMemBKSize) {
113        // not supported
114    }
115
116    #[cfg(dma_can_access_psram)]
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().toggle(|w, bit| w.in_rst().bit(bit));
239    }
240
241    fn set_burst_mode(&self, _burst_mode: BurstConfig) {}
242
243    fn set_descr_burst_mode(&self, _burst_mode: bool) {}
244
245    fn set_peripheral(&self, _peripheral: u8) {
246        // no-op
247    }
248
249    fn set_link_addr(&self, address: u32) {
250        self.regs()
251            .in_link()
252            .modify(|_, w| unsafe { w.inlink_addr().bits(address) });
253    }
254
255    fn start(&self) {
256        self.regs()
257            .in_link()
258            .modify(|_, w| w.inlink_start().set_bit());
259    }
260
261    fn stop(&self) {
262        self.regs()
263            .in_link()
264            .modify(|_, w| w.inlink_stop().set_bit());
265    }
266
267    fn restart(&self) {
268        self.regs()
269            .in_link()
270            .modify(|_, w| w.inlink_restart().set_bit());
271    }
272
273    fn set_check_owner(&self, check_owner: Option<bool>) {
274        if check_owner == Some(true) {
275            panic!("Copy DMA does not support checking descriptor ownership");
276        }
277    }
278
279    fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool {
280        self.0.is_compatible_with(peripheral)
281    }
282
283    #[cfg(dma_ext_mem_configurable_block_size)]
284    fn set_ext_mem_block_size(&self, _size: DmaExtMemBKSize) {
285        // not supported
286    }
287
288    #[cfg(dma_can_access_psram)]
289    fn can_access_psram(&self) -> bool {
290        false
291    }
292}
293
294impl RxRegisterAccess for CopyDmaRxChannel<'_> {
295    fn peripheral_interrupt(&self) -> Option<Interrupt> {
296        None
297    }
298
299    fn async_handler(&self) -> Option<InterruptHandler> {
300        None
301    }
302}
303
304impl InterruptAccess<DmaRxInterrupt> for CopyDmaRxChannel<'_> {
305    fn enable_listen(&self, interrupts: EnumSet<DmaRxInterrupt>, enable: bool) {
306        self.regs().int_ena().modify(|_, w| {
307            for interrupt in interrupts {
308                match interrupt {
309                    DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().bit(enable),
310                    DmaRxInterrupt::ErrorEof => unimplemented!(),
311                    DmaRxInterrupt::DescriptorError => w.in_dscr_err().bit(enable),
312                    DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().bit(enable),
313                    DmaRxInterrupt::Done => w.in_done().bit(enable),
314                };
315            }
316            w
317        });
318    }
319
320    fn is_listening(&self) -> EnumSet<DmaRxInterrupt> {
321        let mut result = EnumSet::new();
322
323        let int_ena = self.regs().int_ena().read();
324        if int_ena.in_dscr_err().bit_is_set() {
325            result |= DmaRxInterrupt::DescriptorError;
326        }
327        if int_ena.in_dscr_err().bit_is_set() {
328            result |= DmaRxInterrupt::DescriptorEmpty;
329        }
330        if int_ena.in_suc_eof().bit_is_set() {
331            result |= DmaRxInterrupt::SuccessfulEof;
332        }
333        if int_ena.in_done().bit_is_set() {
334            result |= DmaRxInterrupt::Done;
335        }
336
337        result
338    }
339
340    fn clear(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
341        self.regs().int_clr().write(|w| {
342            for interrupt in interrupts.into() {
343                match interrupt {
344                    DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().clear_bit_by_one(),
345                    DmaRxInterrupt::ErrorEof => continue,
346                    DmaRxInterrupt::DescriptorError => w.in_dscr_err().clear_bit_by_one(),
347                    DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().clear_bit_by_one(),
348                    DmaRxInterrupt::Done => w.in_done().clear_bit_by_one(),
349                };
350            }
351            w
352        });
353    }
354
355    fn pending_interrupts(&self) -> EnumSet<DmaRxInterrupt> {
356        let mut result = EnumSet::new();
357
358        let int_raw = self.regs().int_raw().read();
359        if int_raw.in_dscr_err().bit_is_set() {
360            result |= DmaRxInterrupt::DescriptorError;
361        }
362        if int_raw.in_dscr_empty().bit_is_set() {
363            result |= DmaRxInterrupt::DescriptorEmpty;
364        }
365        if int_raw.in_suc_eof().bit_is_set() {
366            result |= DmaRxInterrupt::SuccessfulEof;
367        }
368        if int_raw.in_done().bit_is_set() {
369            result |= DmaRxInterrupt::Done;
370        }
371
372        result
373    }
374
375    fn waker(&self) -> &'static AtomicWaker {
376        self.0.rx_waker()
377    }
378
379    fn is_async(&self) -> bool {
380        self.0.rx_async_flag().load(Ordering::Relaxed)
381    }
382
383    fn set_async(&self, _is_async: bool) {
384        self.0.rx_async_flag().store(_is_async, Ordering::Relaxed);
385    }
386}
387
388impl<'d> DmaChannel for DMA_COPY<'d> {
389    type Rx = CopyDmaRxChannel<'d>;
390    type Tx = CopyDmaTxChannel<'d>;
391    unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx) {
392        (
393            CopyDmaRxChannel(unsafe { Self::steal() }),
394            CopyDmaTxChannel(unsafe { Self::steal() }),
395        )
396    }
397}
398impl DmaChannelExt for DMA_COPY<'_> {
399    fn rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt> {
400        CopyDmaRxChannel(unsafe { Self::steal() })
401    }
402    fn tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
403        CopyDmaTxChannel(unsafe { Self::steal() })
404    }
405}
406impl PdmaChannel for DMA_COPY<'_> {
407    type RegisterBlock = CopyRegisterBlock;
408    fn register_block(&self) -> &Self::RegisterBlock {
409        DMA_COPY::regs()
410    }
411    fn tx_waker(&self) -> &'static AtomicWaker {
412        static WAKER: AtomicWaker = AtomicWaker::new();
413        &WAKER
414    }
415    fn rx_waker(&self) -> &'static AtomicWaker {
416        static WAKER: AtomicWaker = AtomicWaker::new();
417        &WAKER
418    }
419    fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool {
420        let compatible_peripherals = [DmaPeripheral::Aes, DmaPeripheral::Sha];
421        compatible_peripherals.contains(&peripheral)
422    }
423    fn peripheral_interrupt(&self) -> Interrupt {
424        Interrupt::DMA_COPY
425    }
426    fn async_handler(&self) -> InterruptHandler {
427        pub(crate) extern "C" fn __esp_hal_internal_interrupt_handler() {
428            asynch::handle_in_interrupt::<DMA_COPY<'static>>();
429            asynch::handle_out_interrupt::<DMA_COPY<'static>>();
430        }
431        pub(crate) static INTERRUPT_HANDLER: InterruptHandler =
432            InterruptHandler::new(__esp_hal_internal_interrupt_handler, Priority::max());
433        INTERRUPT_HANDLER
434    }
435    fn rx_async_flag(&self) -> &'static AtomicBool {
436        static FLAG: AtomicBool = AtomicBool::new(false);
437        &FLAG
438    }
439    fn tx_async_flag(&self) -> &'static AtomicBool {
440        static FLAG: AtomicBool = AtomicBool::new(false);
441        &FLAG
442    }
443}
444impl<'d> DmaChannelConvert<CopyDmaRxChannel<'d>> for DMA_COPY<'d> {
445    fn degrade(self) -> CopyDmaRxChannel<'d> {
446        CopyDmaRxChannel(self)
447    }
448}
449impl<'d> DmaChannelConvert<CopyDmaTxChannel<'d>> for DMA_COPY<'d> {
450    fn degrade(self) -> CopyDmaTxChannel<'d> {
451        CopyDmaTxChannel(self)
452    }
453}