esp_hal/dma/pdma/
i2s.rs

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