Skip to main content

esp_hal/dma/pdma/
i2s.rs

1use enumset::EnumSet;
2use portable_atomic::{AtomicBool, Ordering};
3
4use crate::{
5    RegisterToggle,
6    asynch::AtomicWaker,
7    dma::{
8        BurstConfig,
9        DmaChannel,
10        DmaPeripheral,
11        DmaRxChannel,
12        DmaRxInterrupt,
13        DmaTxChannel,
14        DmaTxInterrupt,
15        InterruptAccess,
16        PdmaChannel,
17        RegisterAccess,
18        RxRegisterAccess,
19        TxRegisterAccess,
20    },
21    interrupt::InterruptHandler,
22    peripherals::Interrupt,
23    system::Peripheral,
24};
25
26pub(super) type I2sRegisterBlock = crate::pac::i2s0::RegisterBlock;
27
28/// The RX half of an arbitrary I2S DMA channel.
29#[derive(Debug)]
30#[cfg_attr(feature = "defmt", derive(defmt::Format))]
31pub struct AnyI2sDmaRxChannel<'d>(pub(crate) AnyI2sDmaChannel<'d>);
32
33impl AnyI2sDmaRxChannel<'_> {
34    fn regs(&self) -> &I2sRegisterBlock {
35        self.0.register_block()
36    }
37}
38
39impl crate::private::Sealed for AnyI2sDmaRxChannel<'_> {}
40impl DmaRxChannel for AnyI2sDmaRxChannel<'_> {}
41
42/// The TX half of an arbitrary I2S DMA channel.
43#[derive(Debug)]
44#[cfg_attr(feature = "defmt", derive(defmt::Format))]
45pub struct AnyI2sDmaTxChannel<'d>(pub(crate) AnyI2sDmaChannel<'d>);
46
47impl AnyI2sDmaTxChannel<'_> {
48    fn regs(&self) -> &I2sRegisterBlock {
49        self.0.register_block()
50    }
51}
52
53impl crate::private::Sealed for AnyI2sDmaTxChannel<'_> {}
54impl DmaTxChannel for AnyI2sDmaTxChannel<'_> {}
55
56impl RegisterAccess for AnyI2sDmaTxChannel<'_> {
57    fn peripheral_clock(&self) -> Option<Peripheral> {
58        None
59    }
60
61    fn reset(&self) {
62        self.regs().lc_conf().toggle(|w, bit| w.out_rst().bit(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(dma_ext_mem_configurable_block_size)]
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(dma_can_access_psram)]
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().toggle(|w, bit| w.in_rst().bit(bit));
251    }
252
253    fn set_burst_mode(&self, _burst_mode: BurstConfig) {}
254
255    fn set_descr_burst_mode(&self, burst_mode: bool) {
256        self.regs()
257            .lc_conf()
258            .modify(|_, w| w.indscr_burst_en().bit(burst_mode));
259    }
260
261    fn set_link_addr(&self, address: u32) {
262        self.regs()
263            .in_link()
264            .modify(|_, w| unsafe { w.inlink_addr().bits(address) });
265    }
266
267    fn set_peripheral(&self, _peripheral: u8) {
268        // no-op
269    }
270
271    fn start(&self) {
272        self.regs()
273            .in_link()
274            .modify(|_, w| w.inlink_start().set_bit());
275    }
276
277    fn stop(&self) {
278        self.regs()
279            .in_link()
280            .modify(|_, w| w.inlink_stop().set_bit());
281    }
282
283    fn restart(&self) {
284        self.regs()
285            .in_link()
286            .modify(|_, w| w.inlink_restart().set_bit());
287    }
288
289    fn set_check_owner(&self, check_owner: Option<bool>) {
290        self.regs()
291            .lc_conf()
292            .modify(|_, w| w.check_owner().bit(check_owner.unwrap_or(true)));
293    }
294
295    fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool {
296        self.0.is_compatible_with(peripheral)
297    }
298
299    #[cfg(dma_ext_mem_configurable_block_size)]
300    fn set_ext_mem_block_size(&self, size: crate::dma::DmaExtMemBKSize) {
301        self.regs()
302            .lc_conf()
303            .modify(|_, w| unsafe { w.ext_mem_bk_size().bits(size as u8) });
304    }
305
306    #[cfg(dma_can_access_psram)]
307    fn can_access_psram(&self) -> bool {
308        matches!(self.0, AnyI2sDmaChannel(any::Inner::I2s0(_)))
309    }
310}
311
312impl RxRegisterAccess for AnyI2sDmaRxChannel<'_> {
313    fn peripheral_interrupt(&self) -> Option<Interrupt> {
314        Some(self.0.peripheral_interrupt())
315    }
316
317    fn async_handler(&self) -> Option<InterruptHandler> {
318        Some(self.0.async_handler())
319    }
320}
321
322impl InterruptAccess<DmaRxInterrupt> for AnyI2sDmaRxChannel<'_> {
323    fn enable_listen(&self, interrupts: EnumSet<DmaRxInterrupt>, enable: bool) {
324        self.regs().int_ena().modify(|_, w| {
325            for interrupt in interrupts {
326                match interrupt {
327                    DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().bit(enable),
328                    DmaRxInterrupt::ErrorEof => w.in_err_eof().bit(enable),
329                    DmaRxInterrupt::DescriptorError => w.in_dscr_err().bit(enable),
330                    DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().bit(enable),
331                    DmaRxInterrupt::Done => w.in_done().bit(enable),
332                };
333            }
334            w
335        });
336    }
337
338    fn is_listening(&self) -> EnumSet<DmaRxInterrupt> {
339        let mut result = EnumSet::new();
340
341        let int_ena = self.regs().int_ena().read();
342        if int_ena.in_dscr_err().bit_is_set() {
343            result |= DmaRxInterrupt::DescriptorError;
344        }
345        if int_ena.in_dscr_empty().bit_is_set() {
346            result |= DmaRxInterrupt::DescriptorEmpty;
347        }
348        if int_ena.in_suc_eof().bit_is_set() {
349            result |= DmaRxInterrupt::SuccessfulEof;
350        }
351        if int_ena.in_err_eof().bit_is_set() {
352            result |= DmaRxInterrupt::ErrorEof;
353        }
354        if int_ena.in_done().bit_is_set() {
355            result |= DmaRxInterrupt::Done;
356        }
357
358        result
359    }
360
361    fn pending_interrupts(&self) -> EnumSet<DmaRxInterrupt> {
362        let mut result = EnumSet::new();
363
364        let int_raw = self.regs().int_raw().read();
365        if int_raw.in_dscr_err().bit_is_set() {
366            result |= DmaRxInterrupt::DescriptorError;
367        }
368        if int_raw.in_dscr_empty().bit_is_set() {
369            result |= DmaRxInterrupt::DescriptorEmpty;
370        }
371        if int_raw.in_suc_eof().bit_is_set() {
372            result |= DmaRxInterrupt::SuccessfulEof;
373        }
374        if int_raw.in_err_eof().bit_is_set() {
375            result |= DmaRxInterrupt::ErrorEof;
376        }
377        if int_raw.in_done().bit_is_set() {
378            result |= DmaRxInterrupt::Done;
379        }
380
381        result
382    }
383
384    fn clear(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
385        self.regs().int_clr().write(|w| {
386            for interrupt in interrupts.into() {
387                match interrupt {
388                    DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().clear_bit_by_one(),
389                    DmaRxInterrupt::ErrorEof => w.in_err_eof().clear_bit_by_one(),
390                    DmaRxInterrupt::DescriptorError => w.in_dscr_err().clear_bit_by_one(),
391                    DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().clear_bit_by_one(),
392                    DmaRxInterrupt::Done => w.in_done().clear_bit_by_one(),
393                };
394            }
395            w
396        });
397    }
398
399    fn waker(&self) -> &'static AtomicWaker {
400        self.0.rx_waker()
401    }
402
403    fn is_async(&self) -> bool {
404        self.0.rx_async_flag().load(Ordering::Relaxed)
405    }
406
407    fn set_async(&self, _is_async: bool) {
408        self.0.rx_async_flag().store(_is_async, Ordering::Relaxed);
409    }
410}
411
412crate::any_peripheral! {
413    /// An I2S-compatible type-erased DMA channel.
414    pub peripheral AnyI2sDmaChannel<'d> {
415        #[cfg(soc_has_i2s0)]
416        I2s0(crate::peripherals::DMA_I2S0<'d>),
417        #[cfg(soc_has_i2s1)]
418        I2s1(crate::peripherals::DMA_I2S1<'d>),
419    }
420}
421
422impl<'d> DmaChannel for AnyI2sDmaChannel<'d> {
423    type Rx = AnyI2sDmaRxChannel<'d>;
424    type Tx = AnyI2sDmaTxChannel<'d>;
425
426    unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx) {
427        (
428            AnyI2sDmaRxChannel(unsafe { self.clone_unchecked() }),
429            AnyI2sDmaTxChannel(unsafe { self.clone_unchecked() }),
430        )
431    }
432}
433
434impl PdmaChannel for AnyI2sDmaChannel<'_> {
435    type RegisterBlock = I2sRegisterBlock;
436
437    delegate::delegate! {
438        to match &self.0 {
439            #[cfg(soc_has_i2s0)]
440            any::Inner::I2s0(channel) => channel,
441            #[cfg(soc_has_i2s1)]
442            any::Inner::I2s1(channel) => channel,
443        } {
444            fn register_block(&self) -> &I2sRegisterBlock;
445            fn tx_waker(&self) -> &'static AtomicWaker;
446            fn rx_waker(&self) -> &'static AtomicWaker;
447            fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool;
448            fn peripheral_interrupt(&self) -> Interrupt;
449            fn async_handler(&self) -> InterruptHandler;
450            fn rx_async_flag(&self) -> &'static AtomicBool;
451            fn tx_async_flag(&self) -> &'static AtomicBool;
452        }
453    }
454}