1use enumset::EnumSet;
2use portable_atomic::Ordering;
3
4use crate::{
5 RegisterToggle,
6 asynch::AtomicWaker,
7 dma::{
8 BurstConfig,
9 DmaChannel,
10 DmaRxChannel,
11 DmaRxInterrupt,
12 DmaTxChannel,
13 DmaTxInterrupt,
14 InterruptAccess,
15 RegisterAccess,
16 RxRegisterAccess,
17 TxRegisterAccess,
18 },
19 interrupt::InterruptHandler,
20 peripherals::Interrupt,
21 system::PeripheralGuard,
22};
23
24#[doc(hidden)]
26pub struct ChannelInfo {
27 pub(crate) peripheral_interrupt: Interrupt,
28
29 pub(crate) async_handler: InterruptHandler,
30
31 pub(crate) compatible_peripherals: &'static [u8],
33}
34
35pub(crate) struct ChannelState {
37 pub(crate) tx_waker: AtomicWaker,
39
40 pub(crate) rx_waker: AtomicWaker,
42
43 pub(crate) tx_async_flag: portable_atomic::AtomicBool,
45
46 pub(crate) rx_async_flag: portable_atomic::AtomicBool,
48}
49
50pub(super) type I2sRegisterBlock = crate::pac::i2s0::RegisterBlock;
51
52#[derive(Debug)]
54#[cfg_attr(feature = "defmt", derive(defmt::Format))]
55pub struct I2sDmaRxChannel<'d>(pub(crate) I2sDmaChannel<'d>);
56
57impl I2sDmaRxChannel<'_> {
58 fn regs(&self) -> &I2sRegisterBlock {
59 self.0.register_block()
60 }
61}
62
63impl crate::private::Sealed for I2sDmaRxChannel<'_> {}
64impl DmaRxChannel for I2sDmaRxChannel<'_> {}
65
66#[derive(Debug)]
68#[cfg_attr(feature = "defmt", derive(defmt::Format))]
69pub struct I2sDmaTxChannel<'d>(pub(crate) I2sDmaChannel<'d>);
70
71impl I2sDmaTxChannel<'_> {
72 fn regs(&self) -> &I2sRegisterBlock {
73 self.0.register_block()
74 }
75}
76
77impl crate::private::Sealed for I2sDmaTxChannel<'_> {}
78impl DmaTxChannel for I2sDmaTxChannel<'_> {}
79
80impl RegisterAccess for I2sDmaTxChannel<'_> {
81 #[allow(private_interfaces)]
82 fn enable(&self) -> Option<PeripheralGuard> {
83 None
84 }
85
86 fn reset(&self) {
87 self.regs().lc_conf().toggle(|w, bit| w.out_rst().bit(bit));
88 }
89
90 fn set_burst_mode(&self, burst_mode: BurstConfig) {
91 self.regs()
92 .lc_conf()
93 .modify(|_, w| w.out_data_burst_en().bit(burst_mode.is_burst_enabled()));
94 }
95
96 fn set_descr_burst_mode(&self, burst_mode: bool) {
97 self.regs()
98 .lc_conf()
99 .modify(|_, w| w.outdscr_burst_en().bit(burst_mode));
100 }
101
102 fn set_link_addr(&self, address: u32) {
103 self.regs()
104 .out_link()
105 .modify(|_, w| unsafe { w.outlink_addr().bits(address) });
106 }
107
108 fn start(&self) {
109 self.regs()
110 .out_link()
111 .modify(|_, w| w.outlink_start().set_bit());
112 }
113
114 fn stop(&self) {
115 self.regs()
116 .out_link()
117 .modify(|_, w| w.outlink_stop().set_bit());
118 }
119
120 fn restart(&self) {
121 self.regs()
122 .out_link()
123 .modify(|_, w| w.outlink_restart().set_bit());
124 }
125
126 fn set_check_owner(&self, check_owner: Option<bool>) {
127 self.regs()
128 .lc_conf()
129 .modify(|_, w| w.check_owner().bit(check_owner.unwrap_or(true)));
130 }
131
132 #[cfg(dma_ext_mem_configurable_block_size)]
133 fn set_ext_mem_block_size(&self, size: crate::dma::DmaExtMemBKSize) {
134 self.regs()
135 .lc_conf()
136 .modify(|_, w| unsafe { w.ext_mem_bk_size().bits(size as u8) });
137 }
138
139 #[cfg(dma_can_access_psram)]
140 fn can_access_psram(&self) -> bool {
141 matches!(self.0, I2sDmaChannel(any::Inner::I2s0(_)))
142 }
143
144 fn compatible_peripherals(&self) -> &[u8] {
145 self.0.info().compatible_peripherals
146 }
147}
148
149impl TxRegisterAccess for I2sDmaTxChannel<'_> {
150 fn is_fifo_empty(&self) -> bool {
151 cfg_select! {
152 esp32 => self.regs().lc_state0().read().bits() & 0x80000000 != 0,
153 _ => self.regs().lc_state0().read().out_empty().bit_is_set(),
154 }
155 }
156
157 fn set_auto_write_back(&self, enable: bool) {
158 self.regs()
159 .lc_conf()
160 .modify(|_, w| w.out_auto_wrback().bit(enable));
161 }
162
163 fn last_dscr_address(&self) -> usize {
164 self.regs()
165 .out_eof_des_addr()
166 .read()
167 .out_eof_des_addr()
168 .bits() as usize
169 }
170
171 fn peripheral_interrupt(&self) -> Option<Interrupt> {
172 Some(self.0.info().peripheral_interrupt)
173 }
174
175 fn async_handler(&self) -> Option<InterruptHandler> {
176 Some(self.0.info().async_handler)
177 }
178}
179
180impl InterruptAccess<DmaTxInterrupt> for I2sDmaTxChannel<'_> {
181 fn enable_listen(&self, interrupts: EnumSet<DmaTxInterrupt>, enable: bool) {
182 self.regs().int_ena().modify(|_, w| {
183 for interrupt in interrupts {
184 match interrupt {
185 DmaTxInterrupt::TotalEof => w.out_total_eof().bit(enable),
186 DmaTxInterrupt::DescriptorError => w.out_dscr_err().bit(enable),
187 DmaTxInterrupt::Eof => w.out_eof().bit(enable),
188 DmaTxInterrupt::Done => w.out_done().bit(enable),
189 };
190 }
191 w
192 });
193 }
194
195 fn is_listening(&self) -> EnumSet<DmaTxInterrupt> {
196 let mut result = EnumSet::new();
197
198 let int_ena = self.regs().int_ena().read();
199 if int_ena.out_total_eof().bit_is_set() {
200 result |= DmaTxInterrupt::TotalEof;
201 }
202 if int_ena.out_dscr_err().bit_is_set() {
203 result |= DmaTxInterrupt::DescriptorError;
204 }
205 if int_ena.out_eof().bit_is_set() {
206 result |= DmaTxInterrupt::Eof;
207 }
208 if int_ena.out_done().bit_is_set() {
209 result |= DmaTxInterrupt::Done;
210 }
211
212 result
213 }
214
215 fn pending_interrupts(&self) -> EnumSet<DmaTxInterrupt> {
216 let mut result = EnumSet::new();
217
218 let int_raw = self.regs().int_raw().read();
219 if int_raw.out_total_eof().bit_is_set() {
220 result |= DmaTxInterrupt::TotalEof;
221 }
222 if int_raw.out_dscr_err().bit_is_set() {
223 result |= DmaTxInterrupt::DescriptorError;
224 }
225 if int_raw.out_eof().bit_is_set() {
226 result |= DmaTxInterrupt::Eof;
227 }
228 if int_raw.out_done().bit_is_set() {
229 result |= DmaTxInterrupt::Done;
230 }
231
232 result
233 }
234
235 fn clear(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
236 self.regs().int_clr().write(|w| {
237 for interrupt in interrupts.into() {
238 match interrupt {
239 DmaTxInterrupt::TotalEof => w.out_total_eof().clear_bit_by_one(),
240 DmaTxInterrupt::DescriptorError => w.out_dscr_err().clear_bit_by_one(),
241 DmaTxInterrupt::Eof => w.out_eof().clear_bit_by_one(),
242 DmaTxInterrupt::Done => w.out_done().clear_bit_by_one(),
243 };
244 }
245 w
246 });
247 }
248
249 fn waker(&self) -> &'static AtomicWaker {
250 &self.0.state().tx_waker
251 }
252
253 fn is_async(&self) -> bool {
254 self.0.state().tx_async_flag.load(Ordering::Relaxed)
255 }
256
257 fn set_async(&self, is_async: bool) {
258 self.0
259 .state()
260 .tx_async_flag
261 .store(is_async, Ordering::Relaxed);
262 }
263}
264
265impl RegisterAccess for I2sDmaRxChannel<'_> {
266 #[allow(private_interfaces)]
267 fn enable(&self) -> Option<PeripheralGuard> {
268 None
269 }
270
271 fn reset(&self) {
272 self.regs().lc_conf().toggle(|w, bit| w.in_rst().bit(bit));
273 }
274
275 fn set_burst_mode(&self, _burst_mode: BurstConfig) {}
276
277 fn set_descr_burst_mode(&self, burst_mode: bool) {
278 self.regs()
279 .lc_conf()
280 .modify(|_, w| w.indscr_burst_en().bit(burst_mode));
281 }
282
283 fn set_link_addr(&self, address: u32) {
284 self.regs()
285 .in_link()
286 .modify(|_, w| unsafe { w.inlink_addr().bits(address) });
287 }
288
289 fn start(&self) {
290 self.regs()
291 .in_link()
292 .modify(|_, w| w.inlink_start().set_bit());
293 }
294
295 fn stop(&self) {
296 self.regs()
297 .in_link()
298 .modify(|_, w| w.inlink_stop().set_bit());
299 }
300
301 fn restart(&self) {
302 self.regs()
303 .in_link()
304 .modify(|_, w| w.inlink_restart().set_bit());
305 }
306
307 fn set_check_owner(&self, check_owner: Option<bool>) {
308 self.regs()
309 .lc_conf()
310 .modify(|_, w| w.check_owner().bit(check_owner.unwrap_or(true)));
311 }
312
313 #[cfg(dma_ext_mem_configurable_block_size)]
314 fn set_ext_mem_block_size(&self, size: crate::dma::DmaExtMemBKSize) {
315 self.regs()
316 .lc_conf()
317 .modify(|_, w| unsafe { w.ext_mem_bk_size().bits(size as u8) });
318 }
319
320 #[cfg(dma_can_access_psram)]
321 fn can_access_psram(&self) -> bool {
322 matches!(self.0, I2sDmaChannel(any::Inner::I2s0(_)))
323 }
324
325 fn compatible_peripherals(&self) -> &[u8] {
326 self.0.info().compatible_peripherals
327 }
328}
329
330impl RxRegisterAccess for I2sDmaRxChannel<'_> {
331 #[cfg(dma_supports_mem2mem)]
332 fn set_mem2mem_mode(&self, en: bool) {
333 self.regs()
334 .lc_conf()
335 .modify(|_, w| w.mem_trans_en().bit(en));
336 }
337
338 fn peripheral_interrupt(&self) -> Option<Interrupt> {
339 Some(self.0.info().peripheral_interrupt)
340 }
341
342 fn async_handler(&self) -> Option<InterruptHandler> {
343 Some(self.0.info().async_handler)
344 }
345}
346
347impl InterruptAccess<DmaRxInterrupt> for I2sDmaRxChannel<'_> {
348 fn enable_listen(&self, interrupts: EnumSet<DmaRxInterrupt>, enable: bool) {
349 self.regs().int_ena().modify(|_, w| {
350 for interrupt in interrupts {
351 match interrupt {
352 DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().bit(enable),
353 DmaRxInterrupt::ErrorEof => w.in_err_eof().bit(enable),
354 DmaRxInterrupt::DescriptorError => w.in_dscr_err().bit(enable),
355 DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().bit(enable),
356 DmaRxInterrupt::Done => w.in_done().bit(enable),
357 };
358 }
359 w
360 });
361 }
362
363 fn is_listening(&self) -> EnumSet<DmaRxInterrupt> {
364 let mut result = EnumSet::new();
365
366 let int_ena = self.regs().int_ena().read();
367 if int_ena.in_dscr_err().bit_is_set() {
368 result |= DmaRxInterrupt::DescriptorError;
369 }
370 if int_ena.in_dscr_empty().bit_is_set() {
371 result |= DmaRxInterrupt::DescriptorEmpty;
372 }
373 if int_ena.in_suc_eof().bit_is_set() {
374 result |= DmaRxInterrupt::SuccessfulEof;
375 }
376 if int_ena.in_err_eof().bit_is_set() {
377 result |= DmaRxInterrupt::ErrorEof;
378 }
379 if int_ena.in_done().bit_is_set() {
380 result |= DmaRxInterrupt::Done;
381 }
382
383 result
384 }
385
386 fn pending_interrupts(&self) -> EnumSet<DmaRxInterrupt> {
387 let mut result = EnumSet::new();
388
389 let int_raw = self.regs().int_raw().read();
390 if int_raw.in_dscr_err().bit_is_set() {
391 result |= DmaRxInterrupt::DescriptorError;
392 }
393 if int_raw.in_dscr_empty().bit_is_set() {
394 result |= DmaRxInterrupt::DescriptorEmpty;
395 }
396 if int_raw.in_suc_eof().bit_is_set() {
397 result |= DmaRxInterrupt::SuccessfulEof;
398 }
399 if int_raw.in_err_eof().bit_is_set() {
400 result |= DmaRxInterrupt::ErrorEof;
401 }
402 if int_raw.in_done().bit_is_set() {
403 result |= DmaRxInterrupt::Done;
404 }
405
406 result
407 }
408
409 fn clear(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
410 self.regs().int_clr().write(|w| {
411 for interrupt in interrupts.into() {
412 match interrupt {
413 DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().clear_bit_by_one(),
414 DmaRxInterrupt::ErrorEof => w.in_err_eof().clear_bit_by_one(),
415 DmaRxInterrupt::DescriptorError => w.in_dscr_err().clear_bit_by_one(),
416 DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().clear_bit_by_one(),
417 DmaRxInterrupt::Done => w.in_done().clear_bit_by_one(),
418 };
419 }
420 w
421 });
422 }
423
424 fn waker(&self) -> &'static AtomicWaker {
425 &self.0.state().rx_waker
426 }
427
428 fn is_async(&self) -> bool {
429 self.0.state().rx_async_flag.load(Ordering::Relaxed)
430 }
431
432 fn set_async(&self, is_async: bool) {
433 self.0
434 .state()
435 .rx_async_flag
436 .store(is_async, Ordering::Relaxed);
437 }
438}
439
440crate::any_peripheral! {
441 pub peripheral I2sDmaChannel<'d> {
443 #[cfg(soc_has_i2s0)]
444 I2s0(DMA_I2S0<'d>),
445 #[cfg(soc_has_i2s1)]
446 I2s1(DMA_I2S1<'d>),
447 }
448}
449
450impl<'d> DmaChannel for I2sDmaChannel<'d> {
451 type Rx = I2sDmaRxChannel<'d>;
452 type Tx = I2sDmaTxChannel<'d>;
453
454 unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx) {
455 (
456 I2sDmaRxChannel(unsafe { self.clone_unchecked() }),
457 I2sDmaTxChannel(self),
458 )
459 }
460}
461
462impl I2sDmaChannel<'_> {
463 delegate::delegate! {
464 to match &self.0 {
465 #[cfg(soc_has_i2s0)]
466 any::Inner::I2s0(channel) => channel,
467 #[cfg(soc_has_i2s1)]
468 any::Inner::I2s1(channel) => channel,
469 } {
470 fn register_block(&self) -> &I2sRegisterBlock;
471 fn info(&self) -> &'static ChannelInfo;
472 fn state(&self) -> &'static ChannelState;
473 }
474 }
475}
476
477impl<'d> From<I2sDmaChannel<'d>> for I2sDmaRxChannel<'d> {
479 fn from(this: I2sDmaChannel<'d>) -> I2sDmaRxChannel<'d> {
480 I2sDmaRxChannel(this)
481 }
482}
483
484impl<'d> From<I2sDmaChannel<'d>> for I2sDmaTxChannel<'d> {
485 fn from(this: I2sDmaChannel<'d>) -> I2sDmaTxChannel<'d> {
486 I2sDmaTxChannel(this)
487 }
488}
489
490for_each_dma_channel_peri_pair! {
491 ("I2S_DMA", $dma_peri:ident, $peri:ident) => {
492 use crate::peripherals::$dma_peri;
493 impl $dma_peri<'_> {
494 pub(super) fn info(&self) -> &'static ChannelInfo {
495 #[crate::handler(priority = crate::interrupt::Priority::max())]
496 fn interrupt_handler() {
497 crate::dma::asynch::handle_in_interrupt::<$dma_peri<'static>>();
498 crate::dma::asynch::handle_out_interrupt::<$dma_peri<'static>>();
499 }
500
501 static INFO: ChannelInfo = ChannelInfo {
502 peripheral_interrupt: Interrupt::$peri,
503 async_handler: interrupt_handler,
504 compatible_peripherals: &[crate::dma::DmaPeripheral::$peri.0],
505 };
506 &INFO
507 }
508
509 pub(super) fn state(&self) -> &'static ChannelState {
510 static STATE: ChannelState = ChannelState {
511 tx_waker: AtomicWaker::new(),
512 rx_waker: AtomicWaker::new(),
513 tx_async_flag: portable_atomic::AtomicBool::new(false),
514 rx_async_flag: portable_atomic::AtomicBool::new(false),
515 };
516 &STATE
517 }
518 }
519
520 crate::dma::impl_channel_common!(I2sDma, $dma_peri);
521 };
522}