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