1use portable_atomic::{AtomicBool, Ordering};
2
3use crate::{asynch::AtomicWaker, dma::*, peripherals::Interrupt};
4
5pub(super) type I2sRegisterBlock = crate::pac::i2s0::RegisterBlock;
6
7#[derive(Debug)]
9#[cfg_attr(feature = "defmt", derive(defmt::Format))]
10pub struct AnyI2sDmaRxChannel<'d>(pub(crate) AnyI2sDmaChannel<'d>);
11
12impl AnyI2sDmaRxChannel<'_> {
13 fn regs(&self) -> &I2sRegisterBlock {
14 self.0.register_block()
15 }
16}
17
18impl crate::private::Sealed for AnyI2sDmaRxChannel<'_> {}
19impl DmaRxChannel for AnyI2sDmaRxChannel<'_> {}
20
21#[derive(Debug)]
23#[cfg_attr(feature = "defmt", derive(defmt::Format))]
24pub struct AnyI2sDmaTxChannel<'d>(pub(crate) AnyI2sDmaChannel<'d>);
25
26impl AnyI2sDmaTxChannel<'_> {
27 fn regs(&self) -> &I2sRegisterBlock {
28 self.0.register_block()
29 }
30}
31
32impl crate::private::Sealed for AnyI2sDmaTxChannel<'_> {}
33impl DmaTxChannel for AnyI2sDmaTxChannel<'_> {}
34
35impl RegisterAccess for AnyI2sDmaTxChannel<'_> {
36 fn reset(&self) {
37 self.regs().lc_conf().modify(|_, w| w.out_rst().set_bit());
38 self.regs().lc_conf().modify(|_, w| w.out_rst().clear_bit());
39 }
40
41 fn set_burst_mode(&self, burst_mode: BurstConfig) {
42 self.regs()
43 .lc_conf()
44 .modify(|_, w| w.out_data_burst_en().bit(burst_mode.is_burst_enabled()));
45 }
46
47 fn set_descr_burst_mode(&self, burst_mode: bool) {
48 self.regs()
49 .lc_conf()
50 .modify(|_, w| w.outdscr_burst_en().bit(burst_mode));
51 }
52
53 fn set_link_addr(&self, address: u32) {
54 self.regs()
55 .out_link()
56 .modify(|_, w| unsafe { w.outlink_addr().bits(address) });
57 }
58
59 fn set_peripheral(&self, _peripheral: u8) {
60 }
62
63 fn start(&self) {
64 self.regs()
65 .out_link()
66 .modify(|_, w| w.outlink_start().set_bit());
67 }
68
69 fn stop(&self) {
70 self.regs()
71 .out_link()
72 .modify(|_, w| w.outlink_stop().set_bit());
73 }
74
75 fn restart(&self) {
76 self.regs()
77 .out_link()
78 .modify(|_, w| w.outlink_restart().set_bit());
79 }
80
81 fn set_check_owner(&self, check_owner: Option<bool>) {
82 self.regs()
83 .lc_conf()
84 .modify(|_, w| w.check_owner().bit(check_owner.unwrap_or(true)));
85 }
86
87 fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool {
88 self.0.is_compatible_with(peripheral)
89 }
90
91 #[cfg(psram_dma)]
92 fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize) {
93 self.regs()
94 .lc_conf()
95 .modify(|_, w| unsafe { w.ext_mem_bk_size().bits(size as u8) });
96 }
97
98 #[cfg(psram_dma)]
99 fn can_access_psram(&self) -> bool {
100 matches!(self.0, AnyI2sDmaChannel(AnyI2sDmaChannelInner::I2s0(_)))
101 }
102}
103
104impl TxRegisterAccess for AnyI2sDmaTxChannel<'_> {
105 fn is_fifo_empty(&self) -> bool {
106 cfg_if::cfg_if! {
107 if #[cfg(esp32)] {
108 self.regs().lc_state0().read().bits() & 0x80000000 != 0
109 } else {
110 self.regs().lc_state0().read().out_empty().bit_is_set()
111 }
112 }
113 }
114
115 fn set_auto_write_back(&self, enable: bool) {
116 self.regs()
117 .lc_conf()
118 .modify(|_, w| w.out_auto_wrback().bit(enable));
119 }
120
121 fn last_dscr_address(&self) -> usize {
122 self.regs()
123 .out_eof_des_addr()
124 .read()
125 .out_eof_des_addr()
126 .bits() as usize
127 }
128
129 fn peripheral_interrupt(&self) -> Option<Interrupt> {
130 Some(self.0.peripheral_interrupt())
131 }
132
133 fn async_handler(&self) -> Option<InterruptHandler> {
134 Some(self.0.async_handler())
135 }
136}
137
138impl InterruptAccess<DmaTxInterrupt> for AnyI2sDmaTxChannel<'_> {
139 fn enable_listen(&self, interrupts: EnumSet<DmaTxInterrupt>, enable: bool) {
140 self.regs().int_ena().modify(|_, w| {
141 for interrupt in interrupts {
142 match interrupt {
143 DmaTxInterrupt::TotalEof => w.out_total_eof().bit(enable),
144 DmaTxInterrupt::DescriptorError => w.out_dscr_err().bit(enable),
145 DmaTxInterrupt::Eof => w.out_eof().bit(enable),
146 DmaTxInterrupt::Done => w.out_done().bit(enable),
147 };
148 }
149 w
150 });
151 }
152
153 fn is_listening(&self) -> EnumSet<DmaTxInterrupt> {
154 let mut result = EnumSet::new();
155
156 let int_ena = self.regs().int_ena().read();
157 if int_ena.out_total_eof().bit_is_set() {
158 result |= DmaTxInterrupt::TotalEof;
159 }
160 if int_ena.out_dscr_err().bit_is_set() {
161 result |= DmaTxInterrupt::DescriptorError;
162 }
163 if int_ena.out_eof().bit_is_set() {
164 result |= DmaTxInterrupt::Eof;
165 }
166 if int_ena.out_done().bit_is_set() {
167 result |= DmaTxInterrupt::Done;
168 }
169
170 result
171 }
172
173 fn pending_interrupts(&self) -> EnumSet<DmaTxInterrupt> {
174 let mut result = EnumSet::new();
175
176 let int_raw = self.regs().int_raw().read();
177 if int_raw.out_total_eof().bit_is_set() {
178 result |= DmaTxInterrupt::TotalEof;
179 }
180 if int_raw.out_dscr_err().bit_is_set() {
181 result |= DmaTxInterrupt::DescriptorError;
182 }
183 if int_raw.out_eof().bit_is_set() {
184 result |= DmaTxInterrupt::Eof;
185 }
186 if int_raw.out_done().bit_is_set() {
187 result |= DmaTxInterrupt::Done;
188 }
189
190 result
191 }
192
193 fn clear(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
194 self.regs().int_clr().write(|w| {
195 for interrupt in interrupts.into() {
196 match interrupt {
197 DmaTxInterrupt::TotalEof => w.out_total_eof().clear_bit_by_one(),
198 DmaTxInterrupt::DescriptorError => w.out_dscr_err().clear_bit_by_one(),
199 DmaTxInterrupt::Eof => w.out_eof().clear_bit_by_one(),
200 DmaTxInterrupt::Done => w.out_done().clear_bit_by_one(),
201 };
202 }
203 w
204 });
205 }
206
207 fn waker(&self) -> &'static AtomicWaker {
208 self.0.tx_waker()
209 }
210
211 fn is_async(&self) -> bool {
212 self.0.tx_async_flag().load(Ordering::Relaxed)
213 }
214
215 fn set_async(&self, _is_async: bool) {
216 self.0.tx_async_flag().store(_is_async, Ordering::Relaxed);
217 }
218}
219
220impl RegisterAccess for AnyI2sDmaRxChannel<'_> {
221 fn reset(&self) {
222 self.regs().lc_conf().modify(|_, w| w.in_rst().set_bit());
223 self.regs().lc_conf().modify(|_, w| w.in_rst().clear_bit());
224 }
225
226 fn set_burst_mode(&self, _burst_mode: BurstConfig) {}
227
228 fn set_descr_burst_mode(&self, burst_mode: bool) {
229 self.regs()
230 .lc_conf()
231 .modify(|_, w| w.indscr_burst_en().bit(burst_mode));
232 }
233
234 fn set_link_addr(&self, address: u32) {
235 self.regs()
236 .in_link()
237 .modify(|_, w| unsafe { w.inlink_addr().bits(address) });
238 }
239
240 fn set_peripheral(&self, _peripheral: u8) {
241 }
243
244 fn start(&self) {
245 self.regs()
246 .in_link()
247 .modify(|_, w| w.inlink_start().set_bit());
248 }
249
250 fn stop(&self) {
251 self.regs()
252 .in_link()
253 .modify(|_, w| w.inlink_stop().set_bit());
254 }
255
256 fn restart(&self) {
257 self.regs()
258 .in_link()
259 .modify(|_, w| w.inlink_restart().set_bit());
260 }
261
262 fn set_check_owner(&self, check_owner: Option<bool>) {
263 self.regs()
264 .lc_conf()
265 .modify(|_, w| w.check_owner().bit(check_owner.unwrap_or(true)));
266 }
267
268 fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool {
269 self.0.is_compatible_with(peripheral)
270 }
271
272 #[cfg(psram_dma)]
273 fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize) {
274 self.regs()
275 .lc_conf()
276 .modify(|_, w| unsafe { w.ext_mem_bk_size().bits(size as u8) });
277 }
278
279 #[cfg(psram_dma)]
280 fn can_access_psram(&self) -> bool {
281 matches!(self.0, AnyI2sDmaChannel(AnyI2sDmaChannelInner::I2s0(_)))
282 }
283}
284
285impl RxRegisterAccess for AnyI2sDmaRxChannel<'_> {
286 fn peripheral_interrupt(&self) -> Option<Interrupt> {
287 Some(self.0.peripheral_interrupt())
288 }
289
290 fn async_handler(&self) -> Option<InterruptHandler> {
291 Some(self.0.async_handler())
292 }
293}
294
295impl InterruptAccess<DmaRxInterrupt> for AnyI2sDmaRxChannel<'_> {
296 fn enable_listen(&self, interrupts: EnumSet<DmaRxInterrupt>, enable: bool) {
297 self.regs().int_ena().modify(|_, w| {
298 for interrupt in interrupts {
299 match interrupt {
300 DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().bit(enable),
301 DmaRxInterrupt::ErrorEof => w.in_err_eof().bit(enable),
302 DmaRxInterrupt::DescriptorError => w.in_dscr_err().bit(enable),
303 DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().bit(enable),
304 DmaRxInterrupt::Done => w.in_done().bit(enable),
305 };
306 }
307 w
308 });
309 }
310
311 fn is_listening(&self) -> EnumSet<DmaRxInterrupt> {
312 let mut result = EnumSet::new();
313
314 let int_ena = self.regs().int_ena().read();
315 if int_ena.in_dscr_err().bit_is_set() {
316 result |= DmaRxInterrupt::DescriptorError;
317 }
318 if int_ena.in_dscr_empty().bit_is_set() {
319 result |= DmaRxInterrupt::DescriptorEmpty;
320 }
321 if int_ena.in_suc_eof().bit_is_set() {
322 result |= DmaRxInterrupt::SuccessfulEof;
323 }
324 if int_ena.in_err_eof().bit_is_set() {
325 result |= DmaRxInterrupt::ErrorEof;
326 }
327 if int_ena.in_done().bit_is_set() {
328 result |= DmaRxInterrupt::Done;
329 }
330
331 result
332 }
333
334 fn pending_interrupts(&self) -> EnumSet<DmaRxInterrupt> {
335 let mut result = EnumSet::new();
336
337 let int_raw = self.regs().int_raw().read();
338 if int_raw.in_dscr_err().bit_is_set() {
339 result |= DmaRxInterrupt::DescriptorError;
340 }
341 if int_raw.in_dscr_empty().bit_is_set() {
342 result |= DmaRxInterrupt::DescriptorEmpty;
343 }
344 if int_raw.in_suc_eof().bit_is_set() {
345 result |= DmaRxInterrupt::SuccessfulEof;
346 }
347 if int_raw.in_err_eof().bit_is_set() {
348 result |= DmaRxInterrupt::ErrorEof;
349 }
350 if int_raw.in_done().bit_is_set() {
351 result |= DmaRxInterrupt::Done;
352 }
353
354 result
355 }
356
357 fn clear(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
358 self.regs().int_clr().write(|w| {
359 for interrupt in interrupts.into() {
360 match interrupt {
361 DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().clear_bit_by_one(),
362 DmaRxInterrupt::ErrorEof => w.in_err_eof().clear_bit_by_one(),
363 DmaRxInterrupt::DescriptorError => w.in_dscr_err().clear_bit_by_one(),
364 DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().clear_bit_by_one(),
365 DmaRxInterrupt::Done => w.in_done().clear_bit_by_one(),
366 };
367 }
368 w
369 });
370 }
371
372 fn waker(&self) -> &'static AtomicWaker {
373 self.0.rx_waker()
374 }
375
376 fn is_async(&self) -> bool {
377 self.0.rx_async_flag().load(Ordering::Relaxed)
378 }
379
380 fn set_async(&self, _is_async: bool) {
381 self.0.rx_async_flag().store(_is_async, Ordering::Relaxed);
382 }
383}
384
385crate::any_peripheral! {
386 pub peripheral AnyI2sDmaChannel<'d> {
388 I2s0(super::DMA_I2S0<'d>),
389 #[cfg(i2s1)]
390 I2s1(super::DMA_I2S1<'d>),
391 }
392}
393
394impl<'d> DmaChannel for AnyI2sDmaChannel<'d> {
395 type Rx = AnyI2sDmaRxChannel<'d>;
396 type Tx = AnyI2sDmaTxChannel<'d>;
397
398 unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx) {
399 (
400 AnyI2sDmaRxChannel(unsafe { self.clone_unchecked() }),
401 AnyI2sDmaTxChannel(unsafe { self.clone_unchecked() }),
402 )
403 }
404}
405
406impl PdmaChannel for AnyI2sDmaChannel<'_> {
407 type RegisterBlock = I2sRegisterBlock;
408
409 delegate::delegate! {
410 to match &self.0 {
411 AnyI2sDmaChannelInner::I2s0(channel) => channel,
412 #[cfg(i2s1)]
413 AnyI2sDmaChannelInner::I2s1(channel) => channel,
414 } {
415 fn register_block(&self) -> &I2sRegisterBlock;
416 fn tx_waker(&self) -> &'static AtomicWaker;
417 fn rx_waker(&self) -> &'static AtomicWaker;
418 fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool;
419 fn peripheral_interrupt(&self) -> Interrupt;
420 fn async_handler(&self) -> InterruptHandler;
421 fn rx_async_flag(&self) -> &'static AtomicBool;
422 fn tx_async_flag(&self) -> &'static AtomicBool;
423 }
424 }
425}