esp_hal/i2s/
parallel.rs

1//! # Parallel Interface (via I2S)
2//!
3//! ## Overview
4//! The I2S parallel interface allows for high-speed data transfer between the
5//! ESP32 and external devices. It is commonly used to external devices such as
6//! LED matrix, LCD display, and Printer. Only TX is implemented. Each
7//! unit can have up to 8 or 16 data signals (depending on your target hardware)
8//! plus 1 clock signal.
9//!
10//! ## Notes
11//!
12//! Data output is interleaved:
13//! - 8bit: [A, B, C, D] is output as [C, D, A, B]  (i.e., swapped as 16bit
14//!   words)
15//! - 16bit: [A, B, C, D] is output as [B, A, D, C] (i.e., 16bit words are
16//!   swapped)
17#![cfg_attr(esp32, doc = "")]
18#![cfg_attr(
19    esp32,
20    doc = "I2S0 does not support true 8bit parallel output, so if you want to do 8bit"
21)]
22#![cfg_attr(
23    esp32,
24    doc = "you should use I2S1.  If you have to use I2S0, it will only output the even"
25)]
26#![cfg_attr(esp32, doc = "bytes! so [A, B, C, D] will be output as [A, C]!!!!")]
27#![cfg_attr(esp32, doc = "")]
28//! ## Configuration
29//!
30//! The driver uses DMA (Direct Memory Access) for efficient data transfer and
31//! supports various configurations, such as different data formats, standards
32//! (e.g., Philips) and pin configurations. It relies on other peripheral
33//! modules, such as
34//!   - `GPIO`
35//!   - `DMA`
36//!   - `system` (to configure and enable the I2S peripheral)
37//!
38//! ## Examples
39//!
40//! ```rust, no_run
41#![doc = crate::before_snippet!()]
42//! # use esp_hal::dma::DmaTxBuf;
43//! # use esp_hal::dma_buffers;
44//! # use esp_hal::delay::Delay;
45//! # use esp_hal::i2s::parallel::{I2sParallel, TxEightBits};
46//!
47//! const BUFFER_SIZE: usize = 256;
48//!
49//! let delay = Delay::new();
50//! let dma_channel = peripherals.DMA_I2S1;
51//! let i2s = peripherals.I2S1;
52//! let clock = peripherals.GPIO25;
53//!
54//! let pins = TxEightBits::new(
55//!     peripherals.GPIO16,
56//!     peripherals.GPIO4,
57//!     peripherals.GPIO17,
58//!     peripherals.GPIO18,
59//!     peripherals.GPIO5,
60//!     peripherals.GPIO19,
61//!     peripherals.GPIO12,
62//!     peripherals.GPIO14,
63//! );
64//!
65//! let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, BUFFER_SIZE);
66//! let mut parallel = I2sParallel::new(
67//!     i2s,
68//!     dma_channel,
69//!     Rate::from_mhz(1),
70//!     pins,
71//!     clock,
72//! ).into_async();
73//!
74//! for (i, data) in tx_buffer.chunks_mut(4).enumerate() {
75//!     let offset = i * 4;
76//!     // i2s parallel driver expects the buffer to be interleaved
77//!     data[0] = (offset + 2) as u8;
78//!     data[1] = (offset + 3) as u8;
79//!     data[2] = offset as u8;
80//!     data[3] = (offset + 1) as u8;
81//! }
82//!
83//! let mut tx_buf: DmaTxBuf =
84//!     DmaTxBuf::new(tx_descriptors, tx_buffer).expect("DmaTxBuf::new failed");
85//!
86//! // Sending 256 bytes.
87//! loop {
88//!     let xfer = match parallel.send(tx_buf) {
89//!         Ok(xfer) => xfer,
90//!         Err(_) => {
91//!             panic!("Failed to send buffer");
92//!         }
93//!     };
94//!     (parallel, tx_buf) = xfer.wait();
95//!     delay.delay_millis(10);
96//! }
97//! # }
98//! ```
99//!
100use core::{
101    mem::ManuallyDrop,
102    ops::{Deref, DerefMut},
103};
104
105use crate::{
106    Async,
107    Blocking,
108    DriverMode,
109    dma::{
110        Channel,
111        ChannelTx,
112        DmaChannelFor,
113        DmaEligible,
114        DmaError,
115        DmaTxBuffer,
116        PeripheralTxChannel,
117        asynch::DmaTxFuture,
118    },
119    gpio::{
120        OutputConfig,
121        OutputSignal,
122        interconnect::{self, PeripheralOutput},
123    },
124    i2s::{AnyI2s, AnyI2sInner},
125    pac::i2s0::RegisterBlock,
126    peripherals::{I2S0, I2S1},
127    system::PeripheralGuard,
128    time::Rate,
129};
130
131#[doc(hidden)]
132pub trait TxPins<'d> {
133    fn bus_width(&self) -> u8;
134    fn configure(&mut self, instance: &(impl Instance + 'd));
135}
136
137/// Represents a group of 16 output pins configured for 16-bit parallel data
138/// transmission.
139pub struct TxSixteenBits<'d> {
140    pins: [interconnect::OutputSignal<'d>; 16],
141}
142
143impl<'d> TxSixteenBits<'d> {
144    #[allow(clippy::too_many_arguments)]
145    /// Creates a new `TxSixteenBits` instance with the provided output pins.
146    pub fn new(
147        pin_0: impl PeripheralOutput<'d>,
148        pin_1: impl PeripheralOutput<'d>,
149        pin_2: impl PeripheralOutput<'d>,
150        pin_3: impl PeripheralOutput<'d>,
151        pin_4: impl PeripheralOutput<'d>,
152        pin_5: impl PeripheralOutput<'d>,
153        pin_6: impl PeripheralOutput<'d>,
154        pin_7: impl PeripheralOutput<'d>,
155        pin_8: impl PeripheralOutput<'d>,
156        pin_9: impl PeripheralOutput<'d>,
157        pin_10: impl PeripheralOutput<'d>,
158        pin_11: impl PeripheralOutput<'d>,
159        pin_12: impl PeripheralOutput<'d>,
160        pin_13: impl PeripheralOutput<'d>,
161        pin_14: impl PeripheralOutput<'d>,
162        pin_15: impl PeripheralOutput<'d>,
163    ) -> Self {
164        Self {
165            pins: [
166                pin_0.into(),
167                pin_1.into(),
168                pin_2.into(),
169                pin_3.into(),
170                pin_4.into(),
171                pin_5.into(),
172                pin_6.into(),
173                pin_7.into(),
174                pin_8.into(),
175                pin_9.into(),
176                pin_10.into(),
177                pin_11.into(),
178                pin_12.into(),
179                pin_13.into(),
180                pin_14.into(),
181                pin_15.into(),
182            ],
183        }
184    }
185}
186
187impl<'d> TxPins<'d> for TxSixteenBits<'d> {
188    fn bus_width(&self) -> u8 {
189        self.pins.len() as u8
190    }
191
192    fn configure(&mut self, instance: &(impl Instance + 'd)) {
193        let bits = self.bus_width();
194        for (i, pin) in self.pins.iter_mut().enumerate() {
195            pin.apply_output_config(&OutputConfig::default());
196            pin.set_output_enable(true);
197            instance.data_out_signal(i, bits).connect_to(pin);
198        }
199    }
200}
201
202/// Represents a group of 8 output pins configured for 8-bit parallel data
203/// transmission.
204pub struct TxEightBits<'d> {
205    pins: [interconnect::OutputSignal<'d>; 8],
206}
207
208impl<'d> TxEightBits<'d> {
209    #[allow(clippy::too_many_arguments)]
210    /// Creates a new `TxSEightBits` instance with the provided output pins.
211    pub fn new(
212        pin_0: impl PeripheralOutput<'d>,
213        pin_1: impl PeripheralOutput<'d>,
214        pin_2: impl PeripheralOutput<'d>,
215        pin_3: impl PeripheralOutput<'d>,
216        pin_4: impl PeripheralOutput<'d>,
217        pin_5: impl PeripheralOutput<'d>,
218        pin_6: impl PeripheralOutput<'d>,
219        pin_7: impl PeripheralOutput<'d>,
220    ) -> Self {
221        Self {
222            pins: [
223                pin_0.into(),
224                pin_1.into(),
225                pin_2.into(),
226                pin_3.into(),
227                pin_4.into(),
228                pin_5.into(),
229                pin_6.into(),
230                pin_7.into(),
231            ],
232        }
233    }
234}
235
236impl<'d> TxPins<'d> for TxEightBits<'d> {
237    fn bus_width(&self) -> u8 {
238        self.pins.len() as u8
239    }
240
241    fn configure(&mut self, instance: &(impl Instance + 'd)) {
242        let bits = self.bus_width();
243        for (i, pin) in self.pins.iter_mut().enumerate() {
244            pin.apply_output_config(&OutputConfig::default());
245            pin.set_output_enable(true);
246            instance.data_out_signal(i, bits).connect_to(pin);
247        }
248    }
249}
250
251/// I2S Parallel Interface
252pub struct I2sParallel<'d, Dm>
253where
254    Dm: DriverMode,
255{
256    instance: AnyI2s<'d>,
257    tx_channel: ChannelTx<Dm, PeripheralTxChannel<AnyI2s<'d>>>,
258    _guard: PeripheralGuard,
259}
260
261impl<'d> I2sParallel<'d, Blocking> {
262    /// Create a new I2S Parallel Interface
263    pub fn new(
264        i2s: impl Instance + 'd,
265        channel: impl DmaChannelFor<AnyI2s<'d>>,
266        frequency: Rate,
267        mut pins: impl TxPins<'d>,
268        clock_pin: impl PeripheralOutput<'d>,
269    ) -> Self {
270        let channel = Channel::new(channel.degrade());
271        channel.runtime_ensure_compatible(&i2s);
272
273        let i2s = i2s.degrade();
274
275        let guard = PeripheralGuard::new(i2s.peripheral());
276
277        // configure the I2S peripheral for parallel mode
278        i2s.setup(frequency, pins.bus_width());
279        // setup the clock pin
280        let clock_pin = clock_pin.into();
281
282        clock_pin.apply_output_config(&OutputConfig::default());
283        clock_pin.set_output_enable(true);
284
285        i2s.ws_signal().connect_to(&clock_pin);
286
287        pins.configure(&i2s);
288        Self {
289            instance: i2s,
290            tx_channel: channel.tx,
291            _guard: guard,
292        }
293    }
294
295    /// Converts the I2S instance into async mode.
296    pub fn into_async(self) -> I2sParallel<'d, Async> {
297        I2sParallel {
298            instance: self.instance,
299            tx_channel: self.tx_channel.into_async(),
300            _guard: self._guard,
301        }
302    }
303}
304
305impl<'d> I2sParallel<'d, Async> {
306    /// Converts the I2S instance into async mode.
307    pub fn into_blocking(self) -> I2sParallel<'d, Blocking> {
308        I2sParallel {
309            instance: self.instance,
310            tx_channel: self.tx_channel.into_blocking(),
311            _guard: self._guard,
312        }
313    }
314}
315
316impl<'d, Dm> I2sParallel<'d, Dm>
317where
318    Dm: DriverMode,
319{
320    /// Write data to the I2S peripheral
321    pub fn send<BUF: DmaTxBuffer>(
322        mut self,
323        mut data: BUF,
324    ) -> Result<I2sParallelTransfer<'d, BUF, Dm>, (DmaError, Self, BUF)> {
325        self.instance.tx_reset();
326        self.instance.tx_fifo_reset();
327        let result = unsafe {
328            self.tx_channel
329                .prepare_transfer(self.instance.dma_peripheral(), &mut data)
330        }
331        .and_then(|_| self.tx_channel.start_transfer());
332        if let Err(err) = result {
333            return Err((err, self, data));
334        }
335        self.instance.tx_start();
336        Ok(I2sParallelTransfer {
337            i2s: ManuallyDrop::new(self),
338            buf_view: ManuallyDrop::new(data.into_view()),
339        })
340    }
341}
342
343/// Represents an ongoing (or potentially finished) transfer using the i2s
344/// parallel interface
345pub struct I2sParallelTransfer<'d, BUF, Dm>
346where
347    BUF: DmaTxBuffer,
348    Dm: DriverMode,
349{
350    i2s: ManuallyDrop<I2sParallel<'d, Dm>>,
351    buf_view: ManuallyDrop<BUF::View>,
352}
353
354impl<'d, BUF, Dm> I2sParallelTransfer<'d, BUF, Dm>
355where
356    BUF: DmaTxBuffer,
357    Dm: DriverMode,
358{
359    /// Returns true when [Self::wait] will not block.
360    pub fn is_done(&self) -> bool {
361        self.i2s.instance.is_tx_done()
362    }
363
364    /// Wait for the transfer to finish
365    pub fn wait(mut self) -> (I2sParallel<'d, Dm>, BUF) {
366        self.i2s.instance.tx_wait_done();
367        let i2s = unsafe { ManuallyDrop::take(&mut self.i2s) };
368        let view = unsafe { ManuallyDrop::take(&mut self.buf_view) };
369        core::mem::forget(self);
370        (i2s, BUF::from_view(view))
371    }
372
373    fn stop_peripherals(&mut self) {
374        self.i2s.instance.tx_stop();
375        self.i2s.tx_channel.stop_transfer();
376    }
377}
378
379impl<BUF> I2sParallelTransfer<'_, BUF, Async>
380where
381    BUF: DmaTxBuffer,
382{
383    /// Wait for the transfer to finish
384    pub async fn wait_for_done(&mut self) -> Result<(), DmaError> {
385        DmaTxFuture::new(&mut self.i2s.tx_channel).await
386    }
387}
388
389impl<BUF, Dm> Deref for I2sParallelTransfer<'_, BUF, Dm>
390where
391    BUF: DmaTxBuffer,
392    Dm: DriverMode,
393{
394    type Target = BUF::View;
395
396    fn deref(&self) -> &Self::Target {
397        &self.buf_view
398    }
399}
400
401impl<BUF, Dm> DerefMut for I2sParallelTransfer<'_, BUF, Dm>
402where
403    BUF: DmaTxBuffer,
404    Dm: DriverMode,
405{
406    fn deref_mut(&mut self) -> &mut Self::Target {
407        &mut self.buf_view
408    }
409}
410
411impl<BUF, Dm> Drop for I2sParallelTransfer<'_, BUF, Dm>
412where
413    BUF: DmaTxBuffer,
414    Dm: DriverMode,
415{
416    fn drop(&mut self) {
417        self.stop_peripherals();
418
419        // SAFETY: This is Drop, we know that self.i2s and self.buf_view
420        // won't be touched again.
421        let view = unsafe {
422            ManuallyDrop::drop(&mut self.i2s);
423            ManuallyDrop::take(&mut self.buf_view)
424        };
425        let _ = BUF::from_view(view);
426    }
427}
428
429#[doc(hidden)]
430#[derive(Debug)]
431pub struct I2sClockDividers {
432    pub mclk_divider: u32,
433    pub bclk_divider: u32,
434    pub denominator: u32,
435    pub numerator: u32,
436}
437
438fn calculate_clock(sample_rate: Rate, data_bits: u8) -> I2sClockDividers {
439    // this loosely corresponds to `i2s_std_calculate_clock` and
440    // `i2s_ll_tx_set_mclk` in esp-idf
441    //
442    // main difference is we are using fixed-point arithmetic here
443    // plus adjusted for parallel interface clocking
444
445    let sclk = crate::soc::constants::I2S_SCLK; // for now it's fixed 160MHz and 96MHz (just H2)
446
447    let rate = sample_rate.as_hz();
448
449    let mclk = rate * 2;
450    let bclk_divider: u32 = if data_bits == 8 { 2 } else { 1 };
451    let mut mclk_divider = sclk / mclk;
452
453    let mut ma: u32;
454    let mut mb: u32;
455    let mut denominator: u32 = 0;
456    let mut numerator: u32 = 0;
457
458    let freq_diff = sclk.abs_diff(mclk * mclk_divider);
459
460    if freq_diff != 0 {
461        let decimal = freq_diff as u64 * 10000 / mclk as u64;
462        // Carry bit if the decimal is greater than 1.0 - 1.0 / (63.0 * 2) = 125.0 /
463        // 126.0
464        if decimal > 1250000 / 126 {
465            mclk_divider += 1;
466        } else {
467            let mut min: u32 = !0;
468
469            for a in 2..=crate::i2s::master::I2S_LL_MCLK_DIVIDER_MAX {
470                let b = (a as u64) * (freq_diff as u64 * 10000u64 / mclk as u64) + 5000;
471                ma = ((freq_diff as u64 * 10000u64 * a as u64) / 10000) as u32;
472                mb = (mclk as u64 * (b / 10000)) as u32;
473
474                if ma == mb {
475                    denominator = a as u32;
476                    numerator = (b / 10000) as u32;
477                    break;
478                }
479
480                if mb.abs_diff(ma) < min {
481                    denominator = a as u32;
482                    numerator = b as u32;
483                    min = mb.abs_diff(ma);
484                }
485            }
486        }
487    }
488
489    I2sClockDividers {
490        mclk_divider,
491        bclk_divider,
492        denominator,
493        numerator,
494    }
495}
496#[doc(hidden)]
497#[allow(private_bounds)]
498pub trait PrivateInstance: DmaEligible {
499    fn regs(&self) -> &RegisterBlock;
500    fn peripheral(&self) -> crate::system::Peripheral;
501    fn ws_signal(&self) -> OutputSignal;
502    fn data_out_signal(&self, i: usize, bits: u8) -> OutputSignal;
503
504    fn rx_reset(&self) {
505        self.regs().conf().modify(|_, w| w.rx_reset().set_bit());
506        self.regs().conf().modify(|_, w| w.rx_reset().clear_bit());
507    }
508
509    fn rx_dma_reset(&self) {
510        self.regs().lc_conf().modify(|_, w| w.in_rst().set_bit());
511        self.regs().lc_conf().modify(|_, w| w.in_rst().clear_bit());
512    }
513
514    fn rx_fifo_reset(&self) {
515        self.regs()
516            .conf()
517            .modify(|_, w| w.rx_fifo_reset().set_bit());
518        self.regs()
519            .conf()
520            .modify(|_, w| w.rx_fifo_reset().clear_bit());
521    }
522
523    fn tx_reset(&self) {
524        self.regs().conf().modify(|_, w| w.tx_reset().set_bit());
525        // without this delay starting a subsequent transfer will hang waiting
526        // for tx_idle to clear (the transfer does not start).
527        // While 20 clocks works for 80MHz cpu but 100 is needed for 240MHz!
528        xtensa_lx::timer::delay(100);
529        self.regs().conf().modify(|_, w| w.tx_reset().clear_bit());
530    }
531
532    fn tx_dma_reset(&self) {
533        self.regs().lc_conf().modify(|_, w| w.out_rst().set_bit());
534        self.regs().lc_conf().modify(|_, w| w.out_rst().clear_bit());
535    }
536
537    fn tx_fifo_reset(&self) {
538        self.regs()
539            .conf()
540            .modify(|_, w| w.tx_fifo_reset().set_bit());
541        self.regs()
542            .conf()
543            .modify(|_, w| w.tx_fifo_reset().clear_bit());
544    }
545
546    fn tx_clear_interrupts(&self) {
547        self.regs().int_clr().write(|w| {
548            w.out_done().clear_bit_by_one();
549            w.out_total_eof().clear_bit_by_one()
550        });
551    }
552
553    fn tx_start(&self) {
554        // wait for data to show up in the fifo
555        while self.regs().int_raw().read().tx_rempty().bit_is_clear() {
556            // wait
557        }
558
559        // without this transfers are not reliable!
560        xtensa_lx::timer::delay(1);
561
562        self.regs().conf().modify(|_, w| w.tx_start().set_bit());
563
564        while self.regs().state().read().tx_idle().bit_is_set() {
565            // wait
566        }
567    }
568
569    fn tx_stop(&self) {
570        self.regs().conf().modify(|_, w| w.tx_start().clear_bit());
571    }
572
573    fn is_tx_done(&self) -> bool {
574        self.regs().state().read().tx_idle().bit_is_set()
575    }
576
577    fn tx_wait_done(&self) {
578        while self.regs().state().read().tx_idle().bit_is_clear() {
579            // wait
580        }
581
582        self.regs().conf().modify(|_, w| w.tx_start().clear_bit());
583        self.regs().int_clr().write(|w| {
584            w.out_done().clear_bit_by_one();
585            w.out_total_eof().clear_bit_by_one()
586        });
587    }
588
589    fn set_clock(&self, clock_settings: I2sClockDividers) {
590        self.regs().clkm_conf().modify(|r, w| unsafe {
591            w.bits(r.bits() | (crate::soc::constants::I2S_DEFAULT_CLK_SRC << 21))
592            // select PLL_160M
593        });
594
595        #[cfg(esp32)]
596        self.regs()
597            .clkm_conf()
598            .modify(|_, w| w.clka_ena().clear_bit());
599
600        self.regs().clkm_conf().modify(|_, w| unsafe {
601            w.clk_en().set_bit();
602            w.clkm_div_num().bits(clock_settings.mclk_divider as u8)
603        });
604
605        self.regs().clkm_conf().modify(|_, w| unsafe {
606            w.clkm_div_a().bits(clock_settings.denominator as u8);
607            w.clkm_div_b().bits(clock_settings.numerator as u8)
608        });
609
610        self.regs().sample_rate_conf().modify(|_, w| unsafe {
611            w.tx_bck_div_num().bits(clock_settings.bclk_divider as u8);
612            w.rx_bck_div_num().bits(clock_settings.bclk_divider as u8)
613        });
614    }
615
616    fn setup(&self, frequency: Rate, bits: u8) {
617        self.set_clock(calculate_clock(frequency, bits));
618
619        // Initialize I2S dev
620        self.rx_reset();
621        self.tx_reset();
622        self.rx_fifo_reset();
623        self.tx_fifo_reset();
624        self.rx_dma_reset();
625        self.tx_dma_reset();
626
627        // clear all bits and enable lcd mode
628        self.regs().conf2().write(|w| {
629            // 8 bit mode needs this or it updates on half clocks!
630            w.lcd_tx_wrx2_en().bit(bits == 8);
631            w.lcd_en().set_bit()
632        });
633
634        self.regs().sample_rate_conf().modify(|_, w| unsafe {
635            w.rx_bits_mod().bits(bits);
636            w.tx_bits_mod().bits(bits)
637        });
638
639        self.regs().fifo_conf().write(|w| unsafe {
640            w.rx_fifo_mod_force_en().set_bit();
641            w.tx_fifo_mod_force_en().set_bit();
642            w.rx_fifo_mod().bits(1);
643            w.tx_fifo_mod().bits(1);
644            w.rx_data_num().bits(32);
645            w.tx_data_num().bits(32);
646            w.dscr_en().set_bit()
647        });
648
649        self.regs().conf1().write(|w| {
650            w.tx_stop_en().set_bit();
651            w.rx_pcm_bypass().set_bit();
652            w.tx_pcm_bypass().set_bit()
653        });
654
655        self.regs().conf_chan().write(|w| unsafe {
656            w.rx_chan_mod().bits(1);
657            w.tx_chan_mod().bits(1)
658        });
659
660        self.regs().conf().modify(|_, w| {
661            w.rx_mono().set_bit();
662            w.tx_mono().set_bit();
663            w.rx_right_first().set_bit();
664            w.tx_right_first().set_bit()
665        });
666        self.regs().timing().reset();
667
668        self.regs().pd_conf().modify(|_, w| {
669            w.fifo_force_pu().set_bit();
670            w.fifo_force_pd().clear_bit()
671        });
672    }
673}
674
675impl PrivateInstance for I2S0<'_> {
676    fn regs(&self) -> &RegisterBlock {
677        unsafe { &*I2S0::PTR.cast::<RegisterBlock>() }
678    }
679
680    fn peripheral(&self) -> crate::system::Peripheral {
681        crate::system::Peripheral::I2s0
682    }
683
684    fn ws_signal(&self) -> OutputSignal {
685        OutputSignal::I2S0O_WS
686    }
687    fn data_out_signal(&self, i: usize, bits: u8) -> OutputSignal {
688        assert!(
689            bits == 8 || bits == 16,
690            "Number of bits must be 8 or 16, got {}",
691            bits
692        );
693
694        // signals for 8bit and 16bit both start at an offset of 8 for I2S0
695        // https://github.com/espressif/esp-idf/blob/9106c43accd9f5e75379f62f12597677213f5023/components/esp_lcd/i80/esp_lcd_panel_io_i2s.c#L701
696        match i + 8 {
697            0 => OutputSignal::I2S0O_DATA_0,
698            1 => OutputSignal::I2S0O_DATA_1,
699            2 => OutputSignal::I2S0O_DATA_2,
700            3 => OutputSignal::I2S0O_DATA_3,
701            4 => OutputSignal::I2S0O_DATA_4,
702            5 => OutputSignal::I2S0O_DATA_5,
703            6 => OutputSignal::I2S0O_DATA_6,
704            7 => OutputSignal::I2S0O_DATA_7,
705            8 => OutputSignal::I2S0O_DATA_8,
706            9 => OutputSignal::I2S0O_DATA_9,
707            10 => OutputSignal::I2S0O_DATA_10,
708            11 => OutputSignal::I2S0O_DATA_11,
709            12 => OutputSignal::I2S0O_DATA_12,
710            13 => OutputSignal::I2S0O_DATA_13,
711            14 => OutputSignal::I2S0O_DATA_14,
712            15 => OutputSignal::I2S0O_DATA_15,
713            16 => OutputSignal::I2S0O_DATA_16,
714            17 => OutputSignal::I2S0O_DATA_17,
715            18 => OutputSignal::I2S0O_DATA_18,
716            19 => OutputSignal::I2S0O_DATA_19,
717            20 => OutputSignal::I2S0O_DATA_20,
718            21 => OutputSignal::I2S0O_DATA_21,
719            22 => OutputSignal::I2S0O_DATA_22,
720            23 => OutputSignal::I2S0O_DATA_23,
721            other => panic!("Invalid I2S0 Dout pin {}", other),
722        }
723    }
724}
725
726impl PrivateInstance for I2S1<'_> {
727    fn regs(&self) -> &RegisterBlock {
728        unsafe { &*I2S1::PTR.cast::<RegisterBlock>() }
729    }
730
731    fn peripheral(&self) -> crate::system::Peripheral {
732        crate::system::Peripheral::I2s1
733    }
734
735    fn ws_signal(&self) -> OutputSignal {
736        OutputSignal::I2S1O_WS
737    }
738    fn data_out_signal(&self, i: usize, bits: u8) -> OutputSignal {
739        assert!(
740            bits == 8 || bits == 16,
741            "Number of bits must be 8 or 16, got {}",
742            bits
743        );
744
745        // signals for 8bit  start at an offset of  8 for 16bit on I2S1
746        let pin_offset = if bits == 16 { 8 } else { 0 };
747
748        match i + pin_offset {
749            0 => OutputSignal::I2S1O_DATA_0,
750            1 => OutputSignal::I2S1O_DATA_1,
751            2 => OutputSignal::I2S1O_DATA_2,
752            3 => OutputSignal::I2S1O_DATA_3,
753            4 => OutputSignal::I2S1O_DATA_4,
754            5 => OutputSignal::I2S1O_DATA_5,
755            6 => OutputSignal::I2S1O_DATA_6,
756            7 => OutputSignal::I2S1O_DATA_7,
757            8 => OutputSignal::I2S1O_DATA_8,
758            9 => OutputSignal::I2S1O_DATA_9,
759            10 => OutputSignal::I2S1O_DATA_10,
760            11 => OutputSignal::I2S1O_DATA_11,
761            12 => OutputSignal::I2S1O_DATA_12,
762            13 => OutputSignal::I2S1O_DATA_13,
763            14 => OutputSignal::I2S1O_DATA_14,
764            15 => OutputSignal::I2S1O_DATA_15,
765            16 => OutputSignal::I2S1O_DATA_16,
766            17 => OutputSignal::I2S1O_DATA_17,
767            18 => OutputSignal::I2S1O_DATA_18,
768            19 => OutputSignal::I2S1O_DATA_19,
769            20 => OutputSignal::I2S1O_DATA_20,
770            21 => OutputSignal::I2S1O_DATA_21,
771            22 => OutputSignal::I2S1O_DATA_22,
772            23 => OutputSignal::I2S1O_DATA_23,
773            other => panic!("Invalid I2S1 Dout pin {}", other),
774        }
775    }
776}
777
778impl PrivateInstance for AnyI2s<'_> {
779    delegate::delegate! {
780        to match &self.0 {
781            AnyI2sInner::I2s0(i2s) => i2s,
782            AnyI2sInner::I2s1(i2s) => i2s,
783        } {
784            fn regs(&self) -> &RegisterBlock;
785            fn peripheral(&self) -> crate::system::Peripheral;
786            fn ws_signal(&self) -> OutputSignal;
787            fn data_out_signal(&self, i: usize, bits: u8) -> OutputSignal ;
788        }
789    }
790}
791
792/// A peripheral singleton compatible with the I2S parallel driver.
793pub trait Instance: PrivateInstance + super::IntoAnyI2s {}
794
795impl Instance for I2S0<'_> {}
796#[cfg(i2s1)]
797impl Instance for I2S1<'_> {}
798impl Instance for AnyI2s<'_> {}