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#[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#[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 }
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 }
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 }
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 }
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}