diff --git a/esp-hal/src/dma/mod.rs b/esp-hal/src/dma/mod.rs index c462cc2d7..d6c693605 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -2980,11 +2980,6 @@ pub(crate) mod asynch { pub fn new(rx: &'a mut RX) -> Self { Self { rx } } - - #[allow(dead_code)] // Dead on the C2 - pub fn rx(&mut self) -> &mut RX { - self.rx - } } impl<'a, RX> core::future::Future for DmaRxFuture<'a, RX> diff --git a/esp-hal/src/i2s.rs b/esp-hal/src/i2s.rs index b6a196a62..cefa135bb 100644 --- a/esp-hal/src/i2s.rs +++ b/esp-hal/src/i2s.rs @@ -534,7 +534,7 @@ where DmaMode: Mode, { fn peripheral_wait_dma(&mut self, _is_rx: bool, _is_tx: bool) { - self.wait_tx_dma_done().ok(); + T::wait_for_tx_done(); } fn peripheral_dma_stop(&mut self) { @@ -575,7 +575,7 @@ where } fn write_bytes(&mut self, data: &[u8]) -> Result<(), Error> { - let ptr = data as *const _ as *const u8; + let ptr = data.as_ptr(); // Reset TX unit and TX FIFO T::reset_tx(); @@ -632,13 +632,6 @@ where Ok(()) } - - fn wait_tx_dma_done(&self) -> Result<(), Error> { - // wait until I2S_TX_IDLE is 1 - T::wait_for_tx_done(); - - Ok(()) - } } impl<'d, T, W, CH, DmaMode> I2sWrite for I2sTx<'d, T, CH, DmaMode> @@ -650,10 +643,7 @@ where { fn write(&mut self, words: &[W]) -> Result<(), Error> { self.write_bytes(unsafe { - core::slice::from_raw_parts( - words as *const _ as *const u8, - core::mem::size_of_val(words), - ) + core::slice::from_raw_parts(words.as_ptr().cast::(), core::mem::size_of_val(words)) }) } } @@ -756,14 +746,14 @@ where } fn read_bytes(&mut self, data: &mut [u8]) -> Result<(), Error> { - let ptr = data as *mut _ as *mut u8; + let ptr = data.as_mut_ptr(); // Reset RX unit and RX FIFO T::reset_rx(); // Enable corresponding interrupts if needed - // configure DMA outlink + // configure DMA inlink unsafe { self.rx_chain.fill_for_rx(false, ptr, data.len())?; self.rx_channel @@ -771,12 +761,10 @@ where .and_then(|_| self.rx_channel.start_transfer())?; } - // set I2S_TX_STOP_EN if needed - - // start: set I2S_TX_START + // start: set I2S_RX_START T::rx_start(data.len()); - // wait until I2S_TX_IDLE is 1 + // wait until I2S_RX_IDLE is 1 T::wait_for_rx_done(); Ok(()) @@ -796,12 +784,12 @@ where return Err(Error::IllegalArgument); } - // Reset TX unit and TX FIFO + // Reset RX unit and RX FIFO T::reset_rx(); // Enable corresponding interrupts if needed - // configure DMA outlink + // configure DMA inlink unsafe { self.rx_chain.fill_for_rx(circular, ptr, len)?; self.rx_channel @@ -809,8 +797,6 @@ where .and_then(|_| self.rx_channel.start_transfer())?; } - // set I2S_TX_STOP_EN if needed - // start: set I2S_RX_START T::rx_start(len); Ok(()) @@ -831,7 +817,7 @@ where self.read_bytes(unsafe { core::slice::from_raw_parts_mut( - words as *mut _ as *mut u8, + words.as_mut_ptr().cast::(), core::mem::size_of_val(words), ) }) @@ -1112,24 +1098,18 @@ mod private { i2s.clkm_conf().modify(|_, w| w.clka_ena().clear_bit()); i2s.clkm_conf().modify(|_, w| unsafe { - w.clk_en() - .set_bit() - .clkm_div_num() - .bits(clock_settings.mclk_divider as u8) + w.clk_en().set_bit(); + w.clkm_div_num().bits(clock_settings.mclk_divider as u8) }); i2s.clkm_conf().modify(|_, w| unsafe { - w.clkm_div_a() - .bits(clock_settings.denominator as u8) - .clkm_div_b() - .bits(clock_settings.numerator as u8) + w.clkm_div_a().bits(clock_settings.denominator as u8); + w.clkm_div_b().bits(clock_settings.numerator as u8) }); i2s.sample_rate_conf().modify(|_, w| unsafe { - w.tx_bck_div_num() - .bits(clock_settings.bclk_divider as u8) - .rx_bck_div_num() - .bits(clock_settings.bclk_divider as u8) + w.tx_bck_div_num().bits(clock_settings.bclk_divider as u8); + w.rx_bck_div_num().bits(clock_settings.bclk_divider as u8) }); } @@ -1147,58 +1127,53 @@ mod private { .modify(|_, w| unsafe { w.rx_bits_mod().bits(data_format.channel_bits()) }); i2s.conf().modify(|_, w| { - w.tx_slave_mod() - .clear_bit() - .rx_slave_mod() - .clear_bit() - .tx_msb_shift() - .set_bit() // ? - .rx_msb_shift() - .set_bit() // ? - .tx_short_sync() - .bit(false) //?? - .rx_short_sync() - .bit(false) //?? - .tx_msb_right() - .clear_bit() - .rx_msb_right() - .clear_bit() - .tx_right_first() - .clear_bit() - .rx_right_first() - .clear_bit() - .tx_mono() - .clear_bit() - .rx_mono() - .clear_bit() - .sig_loopback() - .clear_bit() + w.tx_slave_mod().clear_bit(); + w.rx_slave_mod().clear_bit(); + // If the I2S_RX_MSB_SHIFT bit and the I2S_TX_MSB_SHIFT bit of register + // I2S_CONF_REG are set to 1, respectively, the I2S module will use the Philips + // standard when receiving and transmitting data. + w.tx_msb_shift().set_bit(); + w.rx_msb_shift().set_bit(); + // Short frame synchronization + w.tx_short_sync().bit(false); + w.rx_short_sync().bit(false); + w.tx_msb_right().clear_bit(); + w.rx_msb_right().clear_bit(); + w.tx_right_first().clear_bit(); + w.rx_right_first().clear_bit(); + w.tx_mono().clear_bit(); + w.rx_mono().clear_bit(); + w.sig_loopback().clear_bit() }); i2s.fifo_conf().modify(|_, w| unsafe { - w.tx_fifo_mod() - .bits(fifo_mod) - .tx_fifo_mod_force_en() - .set_bit() - .dscr_en() - .set_bit() - .rx_fifo_mod() - .bits(fifo_mod) - .rx_fifo_mod_force_en() - .set_bit() + w.tx_fifo_mod().bits(fifo_mod); + w.tx_fifo_mod_force_en().set_bit(); + w.dscr_en().set_bit(); + w.rx_fifo_mod().bits(fifo_mod); + w.rx_fifo_mod_force_en().set_bit() }); - i2s.conf_chan() - .modify(|_, w| unsafe { w.tx_chan_mod().bits(0).rx_chan_mod().bits(0) }); // for now only stereo + i2s.conf_chan().modify(|_, w| unsafe { + // for now only stereo + w.tx_chan_mod().bits(0); + w.rx_chan_mod().bits(0) + }); - i2s.conf1() - .modify(|_, w| w.tx_pcm_bypass().set_bit().rx_pcm_bypass().set_bit()); + i2s.conf1().modify(|_, w| { + w.tx_pcm_bypass().set_bit(); + w.rx_pcm_bypass().set_bit() + }); - i2s.pd_conf() - .modify(|_, w| w.fifo_force_pu().set_bit().fifo_force_pd().clear_bit()); + i2s.pd_conf().modify(|_, w| { + w.fifo_force_pu().set_bit(); + w.fifo_force_pd().clear_bit() + }); - i2s.conf2() - .modify(|_, w| w.camera_en().clear_bit().lcd_en().clear_bit()); + i2s.conf2().modify(|_, w| { + w.camera_en().clear_bit(); + w.lcd_en().clear_bit() + }); } fn set_master() { @@ -1213,19 +1188,21 @@ mod private { fn reset_tx() { let i2s = Self::register_block(); - i2s.conf() - .modify(|_, w| w.tx_reset().set_bit().tx_fifo_reset().set_bit()); - i2s.conf() - .modify(|_, w| w.tx_reset().clear_bit().tx_fifo_reset().clear_bit()); + i2s.conf().modify(|_, w| { + w.tx_reset().set_bit(); + w.tx_fifo_reset().set_bit() + }); + i2s.conf().modify(|_, w| { + w.tx_reset().clear_bit(); + w.tx_fifo_reset().clear_bit() + }); i2s.lc_conf().modify(|_, w| w.out_rst().set_bit()); i2s.lc_conf().modify(|_, w| w.out_rst().clear_bit()); i2s.int_clr().write(|w| { - w.out_done() - .clear_bit_by_one() - .out_total_eof() - .clear_bit_by_one() + w.out_done().clear_bit_by_one(); + w.out_total_eof().clear_bit_by_one() }); } @@ -1254,38 +1231,40 @@ mod private { fn reset_rx() { let i2s = Self::register_block(); - i2s.conf() - .modify(|_, w| w.rx_reset().set_bit().rx_fifo_reset().set_bit()); - i2s.conf() - .modify(|_, w| w.rx_reset().clear_bit().rx_fifo_reset().clear_bit()); + i2s.conf().modify(|_, w| { + w.rx_reset().set_bit(); + w.rx_fifo_reset().set_bit() + }); + i2s.conf().modify(|_, w| { + w.rx_reset().clear_bit(); + w.rx_fifo_reset().clear_bit() + }); i2s.lc_conf().modify(|_, w| w.in_rst().set_bit()); i2s.lc_conf().modify(|_, w| w.in_rst().clear_bit()); i2s.int_clr().write(|w| { - w.in_done() - .clear_bit_by_one() - .in_suc_eof() - .clear_bit_by_one() + w.in_done().clear_bit_by_one(); + w.in_suc_eof().clear_bit_by_one() }); } fn rx_start(len: usize) { - #[cfg(not(esp32))] - let len = len - 1; - let i2s = Self::register_block(); i2s.int_clr().write(|w| w.in_suc_eof().clear_bit_by_one()); - #[cfg(not(esp32))] - i2s.rxeof_num() - .modify(|_, w| unsafe { w.rx_eof_num().bits(len as u32) }); + cfg_if::cfg_if! { + if #[cfg(esp32)] { + // On ESP32, the eof_num count in words. + let eof_num = len / 4; + } else { + let eof_num = len - 1; + } + } - // On ESP32, the eof_num count in words. - #[cfg(esp32)] i2s.rxeof_num() - .modify(|_, w| unsafe { w.rx_eof_num().bits((len / 4) as u32) }); + .modify(|_, w| unsafe { w.rx_eof_num().bits(eof_num as u32) }); i2s.conf().modify(|_, w| w.rx_start().set_bit()); } @@ -1432,14 +1411,10 @@ mod private { } i2s.tx_clkm_div_conf().modify(|_, w| unsafe { - w.tx_clkm_div_x() - .bits(clkm_div_x as u16) - .tx_clkm_div_y() - .bits(clkm_div_y as u16) - .tx_clkm_div_yn1() - .bit(clkm_div_yn1 != 0) - .tx_clkm_div_z() - .bits(clkm_div_z as u16) + w.tx_clkm_div_x().bits(clkm_div_x as u16); + w.tx_clkm_div_y().bits(clkm_div_y as u16); + w.tx_clkm_div_yn1().bit(clkm_div_yn1 != 0); + w.tx_clkm_div_z().bits(clkm_div_z as u16) }); i2s.tx_clkm_conf().modify(|_, w| unsafe { @@ -1459,25 +1434,19 @@ mod private { }); i2s.rx_clkm_div_conf().modify(|_, w| unsafe { - w.rx_clkm_div_x() - .bits(clkm_div_x as u16) - .rx_clkm_div_y() - .bits(clkm_div_y as u16) - .rx_clkm_div_yn1() - .bit(clkm_div_yn1 != 0) - .rx_clkm_div_z() - .bits(clkm_div_z as u16) + w.rx_clkm_div_x().bits(clkm_div_x as u16); + w.rx_clkm_div_y().bits(clkm_div_y as u16); + w.rx_clkm_div_yn1().bit(clkm_div_yn1 != 0); + w.rx_clkm_div_z().bits(clkm_div_z as u16) }); i2s.rx_clkm_conf().modify(|_, w| unsafe { - w.rx_clk_active() - .set_bit() - .rx_clk_sel() - .bits(crate::soc::constants::I2S_DEFAULT_CLK_SRC) // for now fixed at 160MHz - .rx_clkm_div_num() - .bits(clock_settings.mclk_divider as u8) - .mclk_sel() - .bit(true) + w.rx_clk_active().set_bit(); + // for now fixed at 160MHz + w.rx_clk_sel() + .bits(crate::soc::constants::I2S_DEFAULT_CLK_SRC); + w.rx_clkm_div_num().bits(clock_settings.mclk_divider as u8); + w.mclk_sel().bit(true) }); i2s.rx_conf1().modify(|_, w| unsafe { @@ -1531,22 +1500,18 @@ mod private { } pcr.i2s_tx_clkm_div_conf().modify(|_, w| unsafe { - w.i2s_tx_clkm_div_x() - .bits(clkm_div_x as u16) - .i2s_tx_clkm_div_y() - .bits(clkm_div_y as u16) - .i2s_tx_clkm_div_yn1() - .bit(clkm_div_yn1 != 0) - .i2s_tx_clkm_div_z() - .bits(clkm_div_z as u16) + w.i2s_tx_clkm_div_x().bits(clkm_div_x as u16); + w.i2s_tx_clkm_div_y().bits(clkm_div_y as u16); + w.i2s_tx_clkm_div_yn1().bit(clkm_div_yn1 != 0); + w.i2s_tx_clkm_div_z().bits(clkm_div_z as u16) }); pcr.i2s_tx_clkm_conf().modify(|_, w| unsafe { - w.i2s_tx_clkm_en() - .set_bit() - .i2s_tx_clkm_sel() - .bits(crate::soc::constants::I2S_DEFAULT_CLK_SRC) // for now fixed at 160MHz for C6 and 96MHz for H2 - .i2s_tx_clkm_div_num() + w.i2s_tx_clkm_en().set_bit(); + // for now fixed at 160MHz for C6 and 96MHz for H2 + w.i2s_tx_clkm_sel() + .bits(crate::soc::constants::I2S_DEFAULT_CLK_SRC); + w.i2s_tx_clkm_div_num() .bits(clock_settings.mclk_divider as u8) }); @@ -1562,25 +1527,20 @@ mod private { }); pcr.i2s_rx_clkm_div_conf().modify(|_, w| unsafe { - w.i2s_rx_clkm_div_x() - .bits(clkm_div_x as u16) - .i2s_rx_clkm_div_y() - .bits(clkm_div_y as u16) - .i2s_rx_clkm_div_yn1() - .bit(clkm_div_yn1 != 0) - .i2s_rx_clkm_div_z() - .bits(clkm_div_z as u16) + w.i2s_rx_clkm_div_x().bits(clkm_div_x as u16); + w.i2s_rx_clkm_div_y().bits(clkm_div_y as u16); + w.i2s_rx_clkm_div_yn1().bit(clkm_div_yn1 != 0); + w.i2s_rx_clkm_div_z().bits(clkm_div_z as u16) }); pcr.i2s_rx_clkm_conf().modify(|_, w| unsafe { - w.i2s_rx_clkm_en() - .set_bit() - .i2s_rx_clkm_sel() - .bits(crate::soc::constants::I2S_DEFAULT_CLK_SRC) // for now fixed at 160MHz for C6 and 96MHz for H2 - .i2s_rx_clkm_div_num() - .bits(clock_settings.mclk_divider as u8) - .i2s_mclk_sel() - .bit(true) + w.i2s_rx_clkm_en().set_bit(); + // for now fixed at 160MHz for C6 and 96MHz for H2 + w.i2s_rx_clkm_sel() + .bits(crate::soc::constants::I2S_DEFAULT_CLK_SRC); + w.i2s_rx_clkm_div_num() + .bits(clock_settings.mclk_divider as u8); + w.i2s_mclk_sel().bit(true) }); #[cfg(not(esp32h2))] i2s.rx_conf1().modify(|_, w| unsafe { @@ -1600,88 +1560,55 @@ mod private { #[allow(clippy::useless_conversion)] i2s.tx_conf1().modify(|_, w| unsafe { w.tx_tdm_ws_width() - .bits((data_format.channel_bits() - 1).into()) - .tx_bits_mod() - .bits(data_format.data_bits() - 1) - .tx_tdm_chan_bits() - .bits(data_format.channel_bits() - 1) - .tx_half_sample_bits() - .bits(data_format.channel_bits() - 1) + .bits((data_format.channel_bits() - 1).into()); + w.tx_bits_mod().bits(data_format.data_bits() - 1); + w.tx_tdm_chan_bits().bits(data_format.channel_bits() - 1); + w.tx_half_sample_bits().bits(data_format.channel_bits() - 1) }); #[cfg(not(esp32h2))] i2s.tx_conf1().modify(|_, w| w.tx_msb_shift().set_bit()); #[cfg(esp32h2)] i2s.tx_conf().modify(|_, w| w.tx_msb_shift().set_bit()); i2s.tx_conf().modify(|_, w| unsafe { - w.tx_mono() - .clear_bit() - .tx_mono_fst_vld() - .set_bit() - .tx_stop_en() - .set_bit() - .tx_chan_equal() - .clear_bit() - .tx_tdm_en() - .set_bit() - .tx_pdm_en() - .clear_bit() - .tx_pcm_bypass() - .set_bit() - .tx_big_endian() - .clear_bit() - .tx_bit_order() - .clear_bit() - .tx_chan_mod() - .bits(0) + w.tx_mono().clear_bit(); + w.tx_mono_fst_vld().set_bit(); + w.tx_stop_en().set_bit(); + w.tx_chan_equal().clear_bit(); + w.tx_tdm_en().set_bit(); + w.tx_pdm_en().clear_bit(); + w.tx_pcm_bypass().set_bit(); + w.tx_big_endian().clear_bit(); + w.tx_bit_order().clear_bit(); + w.tx_chan_mod().bits(0) }); i2s.tx_tdm_ctrl().modify(|_, w| unsafe { - w.tx_tdm_tot_chan_num() - .bits(1) - .tx_tdm_chan0_en() - .set_bit() - .tx_tdm_chan1_en() - .set_bit() - .tx_tdm_chan2_en() - .clear_bit() - .tx_tdm_chan3_en() - .clear_bit() - .tx_tdm_chan4_en() - .clear_bit() - .tx_tdm_chan5_en() - .clear_bit() - .tx_tdm_chan6_en() - .clear_bit() - .tx_tdm_chan7_en() - .clear_bit() - .tx_tdm_chan8_en() - .clear_bit() - .tx_tdm_chan9_en() - .clear_bit() - .tx_tdm_chan10_en() - .clear_bit() - .tx_tdm_chan11_en() - .clear_bit() - .tx_tdm_chan12_en() - .clear_bit() - .tx_tdm_chan13_en() - .clear_bit() - .tx_tdm_chan14_en() - .clear_bit() - .tx_tdm_chan15_en() - .clear_bit() + w.tx_tdm_tot_chan_num().bits(1); + w.tx_tdm_chan0_en().set_bit(); + w.tx_tdm_chan1_en().set_bit(); + w.tx_tdm_chan2_en().clear_bit(); + w.tx_tdm_chan3_en().clear_bit(); + w.tx_tdm_chan4_en().clear_bit(); + w.tx_tdm_chan5_en().clear_bit(); + w.tx_tdm_chan6_en().clear_bit(); + w.tx_tdm_chan7_en().clear_bit(); + w.tx_tdm_chan8_en().clear_bit(); + w.tx_tdm_chan9_en().clear_bit(); + w.tx_tdm_chan10_en().clear_bit(); + w.tx_tdm_chan11_en().clear_bit(); + w.tx_tdm_chan12_en().clear_bit(); + w.tx_tdm_chan13_en().clear_bit(); + w.tx_tdm_chan14_en().clear_bit(); + w.tx_tdm_chan15_en().clear_bit() }); #[allow(clippy::useless_conversion)] i2s.rx_conf1().modify(|_, w| unsafe { w.rx_tdm_ws_width() - .bits((data_format.channel_bits() - 1).into()) - .rx_bits_mod() - .bits(data_format.data_bits() - 1) - .rx_tdm_chan_bits() - .bits(data_format.channel_bits() - 1) - .rx_half_sample_bits() - .bits(data_format.channel_bits() - 1) + .bits((data_format.channel_bits() - 1).into()); + w.rx_bits_mod().bits(data_format.data_bits() - 1); + w.rx_tdm_chan_bits().bits(data_format.channel_bits() - 1); + w.rx_half_sample_bits().bits(data_format.channel_bits() - 1) }); #[cfg(not(esp32h2))] i2s.rx_conf1().modify(|_, w| w.rx_msb_shift().set_bit()); @@ -1689,59 +1616,34 @@ mod private { i2s.rx_conf().modify(|_, w| w.rx_msb_shift().set_bit()); i2s.rx_conf().modify(|_, w| unsafe { - w.rx_mono() - .clear_bit() - .rx_mono_fst_vld() - .set_bit() - .rx_stop_mode() - .bits(2) - .rx_tdm_en() - .set_bit() - .rx_pdm_en() - .clear_bit() - .rx_pcm_bypass() - .set_bit() - .rx_big_endian() - .clear_bit() - .rx_bit_order() - .clear_bit() + w.rx_mono().clear_bit(); + w.rx_mono_fst_vld().set_bit(); + w.rx_stop_mode().bits(2); + w.rx_tdm_en().set_bit(); + w.rx_pdm_en().clear_bit(); + w.rx_pcm_bypass().set_bit(); + w.rx_big_endian().clear_bit(); + w.rx_bit_order().clear_bit() }); i2s.rx_tdm_ctrl().modify(|_, w| unsafe { - w.rx_tdm_tot_chan_num() - .bits(1) - .rx_tdm_pdm_chan0_en() - .set_bit() - .rx_tdm_pdm_chan1_en() - .set_bit() - .rx_tdm_pdm_chan2_en() - .clear_bit() - .rx_tdm_pdm_chan3_en() - .clear_bit() - .rx_tdm_pdm_chan4_en() - .clear_bit() - .rx_tdm_pdm_chan5_en() - .clear_bit() - .rx_tdm_pdm_chan6_en() - .clear_bit() - .rx_tdm_pdm_chan7_en() - .clear_bit() - .rx_tdm_chan8_en() - .clear_bit() - .rx_tdm_chan9_en() - .clear_bit() - .rx_tdm_chan10_en() - .clear_bit() - .rx_tdm_chan11_en() - .clear_bit() - .rx_tdm_chan12_en() - .clear_bit() - .rx_tdm_chan13_en() - .clear_bit() - .rx_tdm_chan14_en() - .clear_bit() - .rx_tdm_chan15_en() - .clear_bit() + w.rx_tdm_tot_chan_num().bits(1); + w.rx_tdm_pdm_chan0_en().set_bit(); + w.rx_tdm_pdm_chan1_en().set_bit(); + w.rx_tdm_pdm_chan2_en().clear_bit(); + w.rx_tdm_pdm_chan3_en().clear_bit(); + w.rx_tdm_pdm_chan4_en().clear_bit(); + w.rx_tdm_pdm_chan5_en().clear_bit(); + w.rx_tdm_pdm_chan6_en().clear_bit(); + w.rx_tdm_pdm_chan7_en().clear_bit(); + w.rx_tdm_chan8_en().clear_bit(); + w.rx_tdm_chan9_en().clear_bit(); + w.rx_tdm_chan10_en().clear_bit(); + w.rx_tdm_chan11_en().clear_bit(); + w.rx_tdm_chan12_en().clear_bit(); + w.rx_tdm_chan13_en().clear_bit(); + w.rx_tdm_chan14_en().clear_bit(); + w.rx_tdm_chan15_en().clear_bit() }); } @@ -1762,13 +1664,19 @@ mod private { fn reset_tx() { let i2s = Self::register_block(); - i2s.tx_conf() - .modify(|_, w| w.tx_reset().set_bit().tx_fifo_reset().set_bit()); - i2s.tx_conf() - .modify(|_, w| w.tx_reset().clear_bit().tx_fifo_reset().clear_bit()); + i2s.tx_conf().modify(|_, w| { + w.tx_reset().set_bit(); + w.tx_fifo_reset().set_bit() + }); + i2s.tx_conf().modify(|_, w| { + w.tx_reset().clear_bit(); + w.tx_fifo_reset().clear_bit() + }); - i2s.int_clr() - .write(|w| w.tx_done().clear_bit_by_one().tx_hung().clear_bit_by_one()); + i2s.int_clr().write(|w| { + w.tx_done().clear_bit_by_one(); + w.tx_hung().clear_bit_by_one() + }); } fn tx_start() { @@ -1792,13 +1700,19 @@ mod private { fn reset_rx() { let i2s = Self::register_block(); - i2s.rx_conf() - .modify(|_, w| w.rx_reset().set_bit().rx_fifo_reset().set_bit()); - i2s.rx_conf() - .modify(|_, w| w.rx_reset().clear_bit().rx_fifo_reset().clear_bit()); + i2s.rx_conf().modify(|_, w| { + w.rx_reset().set_bit(); + w.rx_fifo_reset().set_bit() + }); + i2s.rx_conf().modify(|_, w| { + w.rx_reset().clear_bit(); + w.rx_fifo_reset().clear_bit() + }); - i2s.int_clr() - .write(|w| w.rx_done().clear_bit_by_one().rx_hung().clear_bit_by_one()); + i2s.int_clr().write(|w| { + w.rx_done().clear_bit_by_one(); + w.rx_hung().clear_bit_by_one() + }); } fn rx_start(len: usize) { @@ -2060,7 +1974,7 @@ mod private { } } - #[cfg(any(esp32s3, esp32))] + #[cfg(i2s1)] impl RegBlock for I2S1 { fn register_block() -> &'static RegisterBlock { unsafe { &*I2S1::PTR.cast::() } @@ -2076,7 +1990,7 @@ mod private { } impl super::RegisterAccess for I2S0 {} - #[cfg(any(esp32s3, esp32))] + #[cfg(i2s1)] impl RegisterAccessPrivate for I2S1 { fn set_interrupt_handler(handler: InterruptHandler) { unsafe { crate::peripherals::I2S1::steal() }.bind_i2s1_interrupt(handler.handler()); @@ -2084,7 +1998,7 @@ mod private { .unwrap(); } } - #[cfg(any(esp32s3, esp32))] + #[cfg(i2s1)] impl super::RegisterAccess for I2S1 {} pub trait I2s0Instance {} @@ -2224,10 +2138,10 @@ pub mod asynch { self.tx_chain.fill_for_tx(false, ptr, len)?; future .tx - .prepare_transfer_without_start(T::get_dma_peripheral(), &self.tx_chain)?; + .prepare_transfer_without_start(T::get_dma_peripheral(), &self.tx_chain) + .and_then(|_| future.tx.start_transfer())?; } - future.tx.start_transfer()?; T::tx_start(); future.await?; @@ -2352,27 +2266,21 @@ pub mod asynch { return Err(Error::IllegalArgument); } - // Reset TX unit and TX FIFO + // Reset RX unit and RX FIFO T::reset_rx(); - let mut future = DmaRxFuture::new(&mut self.rx_channel); + let future = DmaRxFuture::new(&mut self.rx_channel); - // configure DMA outlink + // configure DMA inlink unsafe { self.rx_chain.fill_for_rx(false, ptr, len)?; future - .rx() - .prepare_transfer_without_start(T::get_dma_peripheral(), &self.rx_chain)?; + .rx + .prepare_transfer_without_start(T::get_dma_peripheral(), &self.rx_chain) + .and_then(|_| future.rx.start_transfer())?; } - future.rx().start_transfer()?; - - // set I2S_TX_STOP_EN if needed // start: set I2S_RX_START - #[cfg(not(esp32))] - T::rx_start(len - 1); - - #[cfg(esp32)] T::rx_start(len); future.await?; @@ -2393,12 +2301,12 @@ pub mod asynch { return Err(Error::IllegalArgument); } - // Reset TX unit and TX FIFO + // Reset RX unit and RX FIFO T::reset_rx(); // Enable corresponding interrupts if needed - // configure DMA outlink + // configure DMA inlink unsafe { self.rx_chain.fill_for_rx(true, ptr, len)?; self.rx_channel @@ -2406,13 +2314,7 @@ pub mod asynch { .and_then(|_| self.rx_channel.start_transfer())?; } - // set I2S_TX_STOP_EN if needed - // start: set I2S_RX_START - #[cfg(not(esp32))] - T::rx_start(len - 1); - - #[cfg(esp32)] T::rx_start(len); let state = RxCircularState::new(&mut self.rx_chain); diff --git a/hil-test/Cargo.toml b/hil-test/Cargo.toml index c87492402..f14169959 100644 --- a/hil-test/Cargo.toml +++ b/hil-test/Cargo.toml @@ -59,10 +59,6 @@ harness = false name = "i2s" harness = false -[[test]] -name = "i2s_async" -harness = false - [[test]] name = "lcd_cam_i8080" harness = false diff --git a/hil-test/tests/i2s.rs b/hil-test/tests/i2s.rs index 9b8a53c6c..224cf440e 100644 --- a/hil-test/tests/i2s.rs +++ b/hil-test/tests/i2s.rs @@ -1,9 +1,10 @@ //! I2S Loopback Test //! //! This test uses I2S TX to transmit known data to I2S RX (forced to slave mode -//! with loopback mode enabled). It's using circular DMA mode +//! with loopback mode enabled). //% CHIPS: esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 +//% FEATURES: generic-queue #![no_std] #![no_main] @@ -13,11 +14,25 @@ use esp_hal::{ dma::{Dma, DmaPriority}, dma_buffers, gpio::{Io, NoPin}, - i2s::{DataFormat, I2s, I2sReadDma, I2sWriteDma, Standard}, + i2s::{asynch::*, DataFormat, I2s, I2sReadDma, I2sTx, I2sWriteDma, Standard}, + peripherals::I2S0, prelude::*, + Async, }; use hil_test as _; +cfg_if::cfg_if! { + if #[cfg(any(esp32, esp32s2))] { + use esp_hal::dma::I2s0DmaChannel as DmaChannel0; + type DmaChannel0Creator = esp_hal::dma::I2s0DmaChannelCreator; + } else { + use esp_hal::dma::DmaChannel0; + type DmaChannel0Creator = esp_hal::dma::ChannelCreator<0>; + } +} + +const BUFFER_SIZE: usize = 2000; + #[derive(Clone)] struct SampleSource { i: u8, @@ -43,19 +58,68 @@ impl Iterator for SampleSource { } } +#[embassy_executor::task] +async fn writer(tx_buffer: &'static mut [u8], i2s_tx: I2sTx<'static, I2S0, DmaChannel0, Async>) { + let mut samples = SampleSource::new(); + for b in tx_buffer.iter_mut() { + *b = samples.next().unwrap(); + } + + let mut tx_transfer = i2s_tx.write_dma_circular_async(tx_buffer).unwrap(); + + loop { + tx_transfer + .push_with(|buffer| { + for b in buffer.iter_mut() { + *b = samples.next().unwrap(); + } + buffer.len() + }) + .await + .unwrap(); + } +} + +fn enable_loopback() { + unsafe { + let i2s = esp_hal::peripherals::I2S0::steal(); + cfg_if::cfg_if! { + if #[cfg(any(esp32, esp32s2))] { + i2s.conf().modify(|_, w| w.sig_loopback().set_bit()); + i2s.conf().modify(|_, w| w.rx_slave_mod().set_bit()); + } else { + i2s.tx_conf().modify(|_, w| w.sig_loopback().set_bit()); + i2s.rx_conf().modify(|_, w| w.rx_slave_mod().set_bit()); + + i2s.tx_conf().modify(|_, w| w.tx_update().set_bit()); + i2s.rx_conf().modify(|_, w| w.rx_update().set_bit()); + } + } + } +} + #[cfg(test)] -#[embedded_test::tests] +#[embedded_test::tests(executor = esp_hal_embassy::Executor::new())] mod tests { + // defmt::* is load-bearing, it ensures that the assert in dma_buffers! is not + // using defmt's non-const assert. Doing so would result in a compile error. + #[allow(unused_imports)] + use defmt::{assert, assert_eq, *}; + use super::*; - #[test] - fn test_i2s_loopback() { + struct Context { + io: Io, + dma_channel: DmaChannel0Creator, + i2s: I2S0, + } + + #[init] + fn init() -> Context { let peripherals = esp_hal::init(esp_hal::Config::default()); let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let delay = Delay::new(); - let dma = Dma::new(peripherals.DMA); cfg_if::cfg_if! { @@ -66,19 +130,86 @@ mod tests { } } - let (mut rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) = dma_buffers!(16000, 16000); + Context { + io, + dma_channel, + i2s: peripherals.I2S0, + } + } + + #[test] + async fn test_i2s_loopback_async(ctx: Context) { + let spawner = embassy_executor::Spawner::for_current_executor().await; + + let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) = + esp_hal::dma_circular_buffers!(BUFFER_SIZE, BUFFER_SIZE); let i2s = I2s::new( - peripherals.I2S0, + ctx.i2s, Standard::Philips, DataFormat::Data16Channel16, 16000.Hz(), - dma_channel.configure(false, DmaPriority::Priority0), + ctx.dma_channel + .configure_for_async(false, DmaPriority::Priority0), rx_descriptors, tx_descriptors, ); - let (_, dout) = hil_test::common_test_pins!(io); + let (_, dout) = hil_test::common_test_pins!(ctx.io); + + let din = dout.peripheral_input(); + + let i2s_tx = i2s + .i2s_tx + .with_bclk(NoPin) + .with_ws(NoPin) + .with_dout(dout) + .build(); + + let i2s_rx = i2s + .i2s_rx + .with_bclk(NoPin) + .with_ws(NoPin) + .with_din(din) + .build(); + + enable_loopback(); + + let mut rx_transfer = i2s_rx.read_dma_circular_async(rx_buffer).unwrap(); + spawner.must_spawn(writer(tx_buffer, i2s_tx)); + + let mut rcv = [0u8; BUFFER_SIZE]; + let mut sample_idx = 0; + let mut samples = SampleSource::new(); + for _ in 0..30 { + let len = rx_transfer.pop(&mut rcv).await.unwrap(); + for &b in &rcv[..len] { + let expected = samples.next().unwrap(); + assert_eq!( + b, expected, + "Sample #{} does not match ({} != {})", + sample_idx, b, expected + ); + sample_idx += 1; + } + } + } + + #[test] + fn test_i2s_loopback(ctx: Context) { + let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) = dma_buffers!(16000, 16000); + + let i2s = I2s::new( + ctx.i2s, + Standard::Philips, + DataFormat::Data16Channel16, + 16000.Hz(), + ctx.dma_channel.configure(false, DmaPriority::Priority0), + rx_descriptors, + tx_descriptors, + ); + + let (_, dout) = hil_test::common_test_pins!(ctx.io); let din = dout.peripheral_input(); @@ -96,22 +227,7 @@ mod tests { .with_din(din) .build(); - // enable loopback testing - unsafe { - let i2s = esp_hal::peripherals::I2S0::steal(); - cfg_if::cfg_if! { - if #[cfg(esp32s2)] { - i2s.conf().modify(|_, w| w.sig_loopback().set_bit()); - i2s.conf().modify(|_, w| w.rx_slave_mod().set_bit()); - } else { - i2s.tx_conf().modify(|_, w| w.sig_loopback().set_bit()); - i2s.rx_conf().modify(|_, w| w.rx_slave_mod().set_bit()); - - i2s.tx_conf().modify(|_, w| w.tx_update().set_bit()); - i2s.rx_conf().modify(|_, w| w.rx_update().set_bit()); - } - } - } + enable_loopback(); let mut samples = SampleSource::new(); for b in tx_buffer.iter_mut() { @@ -121,14 +237,14 @@ mod tests { let mut rcv = [0u8; 11000]; let mut filler = [0x1u8; 12000]; - let mut rx_transfer = i2s_rx.read_dma_circular(&mut rx_buffer).unwrap(); + let mut rx_transfer = i2s_rx.read_dma_circular(rx_buffer).unwrap(); // trying to pop data before calling `available` should just do nothing assert_eq!(0, rx_transfer.pop(&mut rcv[..100]).unwrap()); // no data available yet assert_eq!(0, rx_transfer.available()); - let mut tx_transfer = i2s_tx.write_dma_circular(&tx_buffer).unwrap(); + let mut tx_transfer = i2s_tx.write_dma_circular(tx_buffer).unwrap(); let mut iteration = 0; let mut sample_idx = 0; @@ -180,7 +296,7 @@ mod tests { if iteration == 1 { // delay to make it likely `available` will need to handle more than one // descriptor next time - delay.delay_millis(160); + Delay::new().delay_millis(160); } } diff --git a/hil-test/tests/i2s_async.rs b/hil-test/tests/i2s_async.rs deleted file mode 100644 index b2157cf24..000000000 --- a/hil-test/tests/i2s_async.rs +++ /dev/null @@ -1,174 +0,0 @@ -//! I2S Loopback Test (Async) -//! -//! This test uses I2S TX to transmit known data to I2S RX (forced to slave mode -//! with loopback mode enabled). It's using circular DMA mode - -//% CHIPS: esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 -//% FEATURES: generic-queue - -#![no_std] -#![no_main] - -use esp_hal::{ - dma::{Dma, DmaPriority}, - gpio::{Io, NoPin}, - i2s::{asynch::*, DataFormat, I2s, I2sTx, Standard}, - peripherals::I2S0, - prelude::*, - Async, -}; -use hil_test as _; - -cfg_if::cfg_if! { - if #[cfg(any(esp32, esp32s2))] { - use esp_hal::dma::I2s0DmaChannel as DmaChannel0; - } else { - use esp_hal::dma::DmaChannel0; - } -} - -const BUFFER_SIZE: usize = 2000; - -#[derive(Clone)] -struct SampleSource { - i: u8, -} - -impl SampleSource { - // choose values which DON'T restart on every descriptor buffer's start - const ADD: u8 = 5; - const CUT_OFF: u8 = 113; - - fn new() -> Self { - Self { i: 0 } - } -} - -impl Iterator for SampleSource { - type Item = u8; - - fn next(&mut self) -> Option { - let i = self.i; - self.i = (i + Self::ADD) % Self::CUT_OFF; - Some(i) - } -} - -#[embassy_executor::task] -async fn writer(tx_buffer: &'static mut [u8], i2s_tx: I2sTx<'static, I2S0, DmaChannel0, Async>) { - let mut samples = SampleSource::new(); - for b in tx_buffer.iter_mut() { - *b = samples.next().unwrap(); - } - - let mut tx_transfer = i2s_tx.write_dma_circular_async(tx_buffer).unwrap(); - - loop { - tx_transfer - .push_with(|buffer| { - for b in buffer.iter_mut() { - *b = samples.next().unwrap(); - } - buffer.len() - }) - .await - .unwrap(); - } -} - -#[cfg(test)] -#[embedded_test::tests(executor = esp_hal_embassy::Executor::new())] -mod tests { - // defmt::* is load-bearing, it ensures that the assert in dma_buffers! is not - // using defmt's non-const assert. Doing so would result in a compile error. - #[allow(unused_imports)] - use defmt::{assert_eq, *}; - - use super::*; - - #[test] - async fn test_i2s_loopback() { - let spawner = embassy_executor::Spawner::for_current_executor().await; - - let peripherals = esp_hal::init(esp_hal::Config::default()); - - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - - let dma = Dma::new(peripherals.DMA); - - cfg_if::cfg_if! { - if #[cfg(any(esp32, esp32s2))] { - let dma_channel = dma.i2s0channel; - } else { - let dma_channel = dma.channel0; - } - } - - let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) = - esp_hal::dma_circular_buffers!(BUFFER_SIZE, BUFFER_SIZE); - - let i2s = I2s::new( - peripherals.I2S0, - Standard::Philips, - DataFormat::Data16Channel16, - 16000.Hz(), - dma_channel.configure_for_async(false, DmaPriority::Priority0), - rx_descriptors, - tx_descriptors, - ); - - let (_, dout) = hil_test::common_test_pins!(io); - - let din = dout.peripheral_input(); - - let i2s_tx = i2s - .i2s_tx - .with_bclk(NoPin) - .with_ws(NoPin) - .with_dout(dout) - .build(); - - let i2s_rx = i2s - .i2s_rx - .with_bclk(NoPin) - .with_ws(NoPin) - .with_din(din) - .build(); - - // enable loopback testing - unsafe { - let i2s = esp_hal::peripherals::I2S0::steal(); - cfg_if::cfg_if! { - if #[cfg(esp32s2)] { - i2s.conf().modify(|_, w| w.sig_loopback().set_bit()); - i2s.conf().modify(|_, w| w.rx_slave_mod().set_bit()); - } else { - i2s.tx_conf().modify(|_, w| w.sig_loopback().set_bit()); - i2s.rx_conf().modify(|_, w| w.rx_slave_mod().set_bit()); - - i2s.tx_conf().modify(|_, w| w.tx_update().set_bit()); - i2s.rx_conf().modify(|_, w| w.rx_update().set_bit()); - } - } - } - - let mut rx_transfer = i2s_rx.read_dma_circular_async(rx_buffer).unwrap(); - spawner.must_spawn(writer(tx_buffer, i2s_tx)); - - let mut rcv = [0u8; BUFFER_SIZE]; - let mut sample_idx = 0; - let mut samples = SampleSource::new(); - for _ in 0..30 { - let len = rx_transfer.pop(&mut rcv).await.unwrap(); - for &b in &rcv[..len] { - let expected = samples.next().unwrap(); - assert_eq!( - b, expected, - "Sample #{} does not match ({} != {})", - sample_idx, b, expected - ); - sample_idx += 1; - } - } - } -}