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