esp_hal/dma/pdma/
i2s.rs

1use portable_atomic::{AtomicBool, Ordering};
2
3use crate::{asynch::AtomicWaker, dma::*, peripherals::Interrupt};
4
5pub(super) type I2sRegisterBlock = crate::pac::i2s0::RegisterBlock;
6
7/// The RX half of an arbitrary I2S DMA channel.
8#[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/// The TX half of an arbitrary I2S DMA channel.
22#[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        // no-op
61    }
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        // no-op
242    }
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    /// An I2S-compatible type-erased DMA channel.
387    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}