Some minor I2S cleanups (#2190)

* Clean up rx_start

* Improve readability of register manipulation

* Enable failing tests on ESP32

* Improve consistency

* Merge tests

* Disable ESP32 for now

* Clean up some cfgs

* Avoid as pointer-casts

* Inline wait_for_dma_done

* Remove a level of indirection

* Fix typos

* Resolve questionmarks
This commit is contained in:
Dániel Buga 2024-09-19 09:33:52 +02:00 committed by GitHub
parent f765a6b094
commit 46be3b19b5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 361 additions and 526 deletions

View File

@ -2980,11 +2980,6 @@ pub(crate) mod asynch {
pub fn new(rx: &'a mut RX) -> Self { pub fn new(rx: &'a mut RX) -> Self {
Self { rx } 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> impl<'a, RX> core::future::Future for DmaRxFuture<'a, RX>

View File

@ -534,7 +534,7 @@ where
DmaMode: Mode, DmaMode: Mode,
{ {
fn peripheral_wait_dma(&mut self, _is_rx: bool, _is_tx: bool) { 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) { fn peripheral_dma_stop(&mut self) {
@ -575,7 +575,7 @@ where
} }
fn write_bytes(&mut self, data: &[u8]) -> Result<(), Error> { 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 // Reset TX unit and TX FIFO
T::reset_tx(); T::reset_tx();
@ -632,13 +632,6 @@ where
Ok(()) 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<W> for I2sTx<'d, T, CH, DmaMode> impl<'d, T, W, CH, DmaMode> I2sWrite<W> for I2sTx<'d, T, CH, DmaMode>
@ -650,10 +643,7 @@ where
{ {
fn write(&mut self, words: &[W]) -> Result<(), Error> { fn write(&mut self, words: &[W]) -> Result<(), Error> {
self.write_bytes(unsafe { self.write_bytes(unsafe {
core::slice::from_raw_parts( core::slice::from_raw_parts(words.as_ptr().cast::<u8>(), core::mem::size_of_val(words))
words as *const _ as *const u8,
core::mem::size_of_val(words),
)
}) })
} }
} }
@ -756,14 +746,14 @@ where
} }
fn read_bytes(&mut self, data: &mut [u8]) -> Result<(), Error> { 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 // Reset RX unit and RX FIFO
T::reset_rx(); T::reset_rx();
// Enable corresponding interrupts if needed // Enable corresponding interrupts if needed
// configure DMA outlink // configure DMA inlink
unsafe { unsafe {
self.rx_chain.fill_for_rx(false, ptr, data.len())?; self.rx_chain.fill_for_rx(false, ptr, data.len())?;
self.rx_channel self.rx_channel
@ -771,12 +761,10 @@ where
.and_then(|_| self.rx_channel.start_transfer())?; .and_then(|_| self.rx_channel.start_transfer())?;
} }
// set I2S_TX_STOP_EN if needed // start: set I2S_RX_START
// start: set I2S_TX_START
T::rx_start(data.len()); T::rx_start(data.len());
// wait until I2S_TX_IDLE is 1 // wait until I2S_RX_IDLE is 1
T::wait_for_rx_done(); T::wait_for_rx_done();
Ok(()) Ok(())
@ -796,12 +784,12 @@ where
return Err(Error::IllegalArgument); return Err(Error::IllegalArgument);
} }
// Reset TX unit and TX FIFO // Reset RX unit and RX FIFO
T::reset_rx(); T::reset_rx();
// Enable corresponding interrupts if needed // Enable corresponding interrupts if needed
// configure DMA outlink // configure DMA inlink
unsafe { unsafe {
self.rx_chain.fill_for_rx(circular, ptr, len)?; self.rx_chain.fill_for_rx(circular, ptr, len)?;
self.rx_channel self.rx_channel
@ -809,8 +797,6 @@ where
.and_then(|_| self.rx_channel.start_transfer())?; .and_then(|_| self.rx_channel.start_transfer())?;
} }
// set I2S_TX_STOP_EN if needed
// start: set I2S_RX_START // start: set I2S_RX_START
T::rx_start(len); T::rx_start(len);
Ok(()) Ok(())
@ -831,7 +817,7 @@ where
self.read_bytes(unsafe { self.read_bytes(unsafe {
core::slice::from_raw_parts_mut( core::slice::from_raw_parts_mut(
words as *mut _ as *mut u8, words.as_mut_ptr().cast::<u8>(),
core::mem::size_of_val(words), 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| w.clka_ena().clear_bit());
i2s.clkm_conf().modify(|_, w| unsafe { i2s.clkm_conf().modify(|_, w| unsafe {
w.clk_en() w.clk_en().set_bit();
.set_bit() w.clkm_div_num().bits(clock_settings.mclk_divider as u8)
.clkm_div_num()
.bits(clock_settings.mclk_divider as u8)
}); });
i2s.clkm_conf().modify(|_, w| unsafe { i2s.clkm_conf().modify(|_, w| unsafe {
w.clkm_div_a() w.clkm_div_a().bits(clock_settings.denominator as u8);
.bits(clock_settings.denominator as u8) w.clkm_div_b().bits(clock_settings.numerator as u8)
.clkm_div_b()
.bits(clock_settings.numerator as u8)
}); });
i2s.sample_rate_conf().modify(|_, w| unsafe { i2s.sample_rate_conf().modify(|_, w| unsafe {
w.tx_bck_div_num() w.tx_bck_div_num().bits(clock_settings.bclk_divider as u8);
.bits(clock_settings.bclk_divider as u8) w.rx_bck_div_num().bits(clock_settings.bclk_divider as u8)
.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()) }); .modify(|_, w| unsafe { w.rx_bits_mod().bits(data_format.channel_bits()) });
i2s.conf().modify(|_, w| { i2s.conf().modify(|_, w| {
w.tx_slave_mod() w.tx_slave_mod().clear_bit();
.clear_bit() w.rx_slave_mod().clear_bit();
.rx_slave_mod() // If the I2S_RX_MSB_SHIFT bit and the I2S_TX_MSB_SHIFT bit of register
.clear_bit() // I2S_CONF_REG are set to 1, respectively, the I2S module will use the Philips
.tx_msb_shift() // standard when receiving and transmitting data.
.set_bit() // ? w.tx_msb_shift().set_bit();
.rx_msb_shift() w.rx_msb_shift().set_bit();
.set_bit() // ? // Short frame synchronization
.tx_short_sync() w.tx_short_sync().bit(false);
.bit(false) //?? w.rx_short_sync().bit(false);
.rx_short_sync() w.tx_msb_right().clear_bit();
.bit(false) //?? w.rx_msb_right().clear_bit();
.tx_msb_right() w.tx_right_first().clear_bit();
.clear_bit() w.rx_right_first().clear_bit();
.rx_msb_right() w.tx_mono().clear_bit();
.clear_bit() w.rx_mono().clear_bit();
.tx_right_first() w.sig_loopback().clear_bit()
.clear_bit()
.rx_right_first()
.clear_bit()
.tx_mono()
.clear_bit()
.rx_mono()
.clear_bit()
.sig_loopback()
.clear_bit()
}); });
i2s.fifo_conf().modify(|_, w| unsafe { i2s.fifo_conf().modify(|_, w| unsafe {
w.tx_fifo_mod() w.tx_fifo_mod().bits(fifo_mod);
.bits(fifo_mod) w.tx_fifo_mod_force_en().set_bit();
.tx_fifo_mod_force_en() w.dscr_en().set_bit();
.set_bit() w.rx_fifo_mod().bits(fifo_mod);
.dscr_en() w.rx_fifo_mod_force_en().set_bit()
.set_bit()
.rx_fifo_mod()
.bits(fifo_mod)
.rx_fifo_mod_force_en()
.set_bit()
}); });
i2s.conf_chan() i2s.conf_chan().modify(|_, w| unsafe {
.modify(|_, w| unsafe { w.tx_chan_mod().bits(0).rx_chan_mod().bits(0) }); // for now only stereo // for now only stereo
w.tx_chan_mod().bits(0);
w.rx_chan_mod().bits(0)
});
i2s.conf1() i2s.conf1().modify(|_, w| {
.modify(|_, w| w.tx_pcm_bypass().set_bit().rx_pcm_bypass().set_bit()); w.tx_pcm_bypass().set_bit();
w.rx_pcm_bypass().set_bit()
});
i2s.pd_conf() i2s.pd_conf().modify(|_, w| {
.modify(|_, w| w.fifo_force_pu().set_bit().fifo_force_pd().clear_bit()); w.fifo_force_pu().set_bit();
w.fifo_force_pd().clear_bit()
});
i2s.conf2() i2s.conf2().modify(|_, w| {
.modify(|_, w| w.camera_en().clear_bit().lcd_en().clear_bit()); w.camera_en().clear_bit();
w.lcd_en().clear_bit()
});
} }
fn set_master() { fn set_master() {
@ -1213,19 +1188,21 @@ mod private {
fn reset_tx() { fn reset_tx() {
let i2s = Self::register_block(); let i2s = Self::register_block();
i2s.conf() i2s.conf().modify(|_, w| {
.modify(|_, w| w.tx_reset().set_bit().tx_fifo_reset().set_bit()); w.tx_reset().set_bit();
i2s.conf() w.tx_fifo_reset().set_bit()
.modify(|_, w| w.tx_reset().clear_bit().tx_fifo_reset().clear_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().set_bit());
i2s.lc_conf().modify(|_, w| w.out_rst().clear_bit()); i2s.lc_conf().modify(|_, w| w.out_rst().clear_bit());
i2s.int_clr().write(|w| { i2s.int_clr().write(|w| {
w.out_done() w.out_done().clear_bit_by_one();
.clear_bit_by_one() w.out_total_eof().clear_bit_by_one()
.out_total_eof()
.clear_bit_by_one()
}); });
} }
@ -1254,38 +1231,40 @@ mod private {
fn reset_rx() { fn reset_rx() {
let i2s = Self::register_block(); let i2s = Self::register_block();
i2s.conf() i2s.conf().modify(|_, w| {
.modify(|_, w| w.rx_reset().set_bit().rx_fifo_reset().set_bit()); w.rx_reset().set_bit();
i2s.conf() w.rx_fifo_reset().set_bit()
.modify(|_, w| w.rx_reset().clear_bit().rx_fifo_reset().clear_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().set_bit());
i2s.lc_conf().modify(|_, w| w.in_rst().clear_bit()); i2s.lc_conf().modify(|_, w| w.in_rst().clear_bit());
i2s.int_clr().write(|w| { i2s.int_clr().write(|w| {
w.in_done() w.in_done().clear_bit_by_one();
.clear_bit_by_one() w.in_suc_eof().clear_bit_by_one()
.in_suc_eof()
.clear_bit_by_one()
}); });
} }
fn rx_start(len: usize) { fn rx_start(len: usize) {
#[cfg(not(esp32))]
let len = len - 1;
let i2s = Self::register_block(); let i2s = Self::register_block();
i2s.int_clr().write(|w| w.in_suc_eof().clear_bit_by_one()); i2s.int_clr().write(|w| w.in_suc_eof().clear_bit_by_one());
#[cfg(not(esp32))] cfg_if::cfg_if! {
i2s.rxeof_num() if #[cfg(esp32)] {
.modify(|_, w| unsafe { w.rx_eof_num().bits(len as u32) }); // 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() 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()); i2s.conf().modify(|_, w| w.rx_start().set_bit());
} }
@ -1432,14 +1411,10 @@ mod private {
} }
i2s.tx_clkm_div_conf().modify(|_, w| unsafe { i2s.tx_clkm_div_conf().modify(|_, w| unsafe {
w.tx_clkm_div_x() w.tx_clkm_div_x().bits(clkm_div_x as u16);
.bits(clkm_div_x as u16) w.tx_clkm_div_y().bits(clkm_div_y as u16);
.tx_clkm_div_y() w.tx_clkm_div_yn1().bit(clkm_div_yn1 != 0);
.bits(clkm_div_y as u16) w.tx_clkm_div_z().bits(clkm_div_z as u16)
.tx_clkm_div_yn1()
.bit(clkm_div_yn1 != 0)
.tx_clkm_div_z()
.bits(clkm_div_z as u16)
}); });
i2s.tx_clkm_conf().modify(|_, w| unsafe { i2s.tx_clkm_conf().modify(|_, w| unsafe {
@ -1459,25 +1434,19 @@ mod private {
}); });
i2s.rx_clkm_div_conf().modify(|_, w| unsafe { i2s.rx_clkm_div_conf().modify(|_, w| unsafe {
w.rx_clkm_div_x() w.rx_clkm_div_x().bits(clkm_div_x as u16);
.bits(clkm_div_x as u16) w.rx_clkm_div_y().bits(clkm_div_y as u16);
.rx_clkm_div_y() w.rx_clkm_div_yn1().bit(clkm_div_yn1 != 0);
.bits(clkm_div_y as u16) w.rx_clkm_div_z().bits(clkm_div_z as u16)
.rx_clkm_div_yn1()
.bit(clkm_div_yn1 != 0)
.rx_clkm_div_z()
.bits(clkm_div_z as u16)
}); });
i2s.rx_clkm_conf().modify(|_, w| unsafe { i2s.rx_clkm_conf().modify(|_, w| unsafe {
w.rx_clk_active() w.rx_clk_active().set_bit();
.set_bit() // for now fixed at 160MHz
.rx_clk_sel() w.rx_clk_sel()
.bits(crate::soc::constants::I2S_DEFAULT_CLK_SRC) // for now fixed at 160MHz .bits(crate::soc::constants::I2S_DEFAULT_CLK_SRC);
.rx_clkm_div_num() w.rx_clkm_div_num().bits(clock_settings.mclk_divider as u8);
.bits(clock_settings.mclk_divider as u8) w.mclk_sel().bit(true)
.mclk_sel()
.bit(true)
}); });
i2s.rx_conf1().modify(|_, w| unsafe { i2s.rx_conf1().modify(|_, w| unsafe {
@ -1531,22 +1500,18 @@ mod private {
} }
pcr.i2s_tx_clkm_div_conf().modify(|_, w| unsafe { pcr.i2s_tx_clkm_div_conf().modify(|_, w| unsafe {
w.i2s_tx_clkm_div_x() w.i2s_tx_clkm_div_x().bits(clkm_div_x as u16);
.bits(clkm_div_x as u16) w.i2s_tx_clkm_div_y().bits(clkm_div_y as u16);
.i2s_tx_clkm_div_y() w.i2s_tx_clkm_div_yn1().bit(clkm_div_yn1 != 0);
.bits(clkm_div_y as u16) w.i2s_tx_clkm_div_z().bits(clkm_div_z as u16)
.i2s_tx_clkm_div_yn1()
.bit(clkm_div_yn1 != 0)
.i2s_tx_clkm_div_z()
.bits(clkm_div_z as u16)
}); });
pcr.i2s_tx_clkm_conf().modify(|_, w| unsafe { pcr.i2s_tx_clkm_conf().modify(|_, w| unsafe {
w.i2s_tx_clkm_en() w.i2s_tx_clkm_en().set_bit();
.set_bit() // for now fixed at 160MHz for C6 and 96MHz for H2
.i2s_tx_clkm_sel() w.i2s_tx_clkm_sel()
.bits(crate::soc::constants::I2S_DEFAULT_CLK_SRC) // for now fixed at 160MHz for C6 and 96MHz for H2 .bits(crate::soc::constants::I2S_DEFAULT_CLK_SRC);
.i2s_tx_clkm_div_num() w.i2s_tx_clkm_div_num()
.bits(clock_settings.mclk_divider as u8) .bits(clock_settings.mclk_divider as u8)
}); });
@ -1562,25 +1527,20 @@ mod private {
}); });
pcr.i2s_rx_clkm_div_conf().modify(|_, w| unsafe { pcr.i2s_rx_clkm_div_conf().modify(|_, w| unsafe {
w.i2s_rx_clkm_div_x() w.i2s_rx_clkm_div_x().bits(clkm_div_x as u16);
.bits(clkm_div_x as u16) w.i2s_rx_clkm_div_y().bits(clkm_div_y as u16);
.i2s_rx_clkm_div_y() w.i2s_rx_clkm_div_yn1().bit(clkm_div_yn1 != 0);
.bits(clkm_div_y as u16) w.i2s_rx_clkm_div_z().bits(clkm_div_z as u16)
.i2s_rx_clkm_div_yn1()
.bit(clkm_div_yn1 != 0)
.i2s_rx_clkm_div_z()
.bits(clkm_div_z as u16)
}); });
pcr.i2s_rx_clkm_conf().modify(|_, w| unsafe { pcr.i2s_rx_clkm_conf().modify(|_, w| unsafe {
w.i2s_rx_clkm_en() w.i2s_rx_clkm_en().set_bit();
.set_bit() // for now fixed at 160MHz for C6 and 96MHz for H2
.i2s_rx_clkm_sel() w.i2s_rx_clkm_sel()
.bits(crate::soc::constants::I2S_DEFAULT_CLK_SRC) // for now fixed at 160MHz for C6 and 96MHz for H2 .bits(crate::soc::constants::I2S_DEFAULT_CLK_SRC);
.i2s_rx_clkm_div_num() w.i2s_rx_clkm_div_num()
.bits(clock_settings.mclk_divider as u8) .bits(clock_settings.mclk_divider as u8);
.i2s_mclk_sel() w.i2s_mclk_sel().bit(true)
.bit(true)
}); });
#[cfg(not(esp32h2))] #[cfg(not(esp32h2))]
i2s.rx_conf1().modify(|_, w| unsafe { i2s.rx_conf1().modify(|_, w| unsafe {
@ -1600,88 +1560,55 @@ mod private {
#[allow(clippy::useless_conversion)] #[allow(clippy::useless_conversion)]
i2s.tx_conf1().modify(|_, w| unsafe { i2s.tx_conf1().modify(|_, w| unsafe {
w.tx_tdm_ws_width() w.tx_tdm_ws_width()
.bits((data_format.channel_bits() - 1).into()) .bits((data_format.channel_bits() - 1).into());
.tx_bits_mod() w.tx_bits_mod().bits(data_format.data_bits() - 1);
.bits(data_format.data_bits() - 1) w.tx_tdm_chan_bits().bits(data_format.channel_bits() - 1);
.tx_tdm_chan_bits() w.tx_half_sample_bits().bits(data_format.channel_bits() - 1)
.bits(data_format.channel_bits() - 1)
.tx_half_sample_bits()
.bits(data_format.channel_bits() - 1)
}); });
#[cfg(not(esp32h2))] #[cfg(not(esp32h2))]
i2s.tx_conf1().modify(|_, w| w.tx_msb_shift().set_bit()); i2s.tx_conf1().modify(|_, w| w.tx_msb_shift().set_bit());
#[cfg(esp32h2)] #[cfg(esp32h2)]
i2s.tx_conf().modify(|_, w| w.tx_msb_shift().set_bit()); i2s.tx_conf().modify(|_, w| w.tx_msb_shift().set_bit());
i2s.tx_conf().modify(|_, w| unsafe { i2s.tx_conf().modify(|_, w| unsafe {
w.tx_mono() w.tx_mono().clear_bit();
.clear_bit() w.tx_mono_fst_vld().set_bit();
.tx_mono_fst_vld() w.tx_stop_en().set_bit();
.set_bit() w.tx_chan_equal().clear_bit();
.tx_stop_en() w.tx_tdm_en().set_bit();
.set_bit() w.tx_pdm_en().clear_bit();
.tx_chan_equal() w.tx_pcm_bypass().set_bit();
.clear_bit() w.tx_big_endian().clear_bit();
.tx_tdm_en() w.tx_bit_order().clear_bit();
.set_bit() w.tx_chan_mod().bits(0)
.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)
}); });
i2s.tx_tdm_ctrl().modify(|_, w| unsafe { i2s.tx_tdm_ctrl().modify(|_, w| unsafe {
w.tx_tdm_tot_chan_num() w.tx_tdm_tot_chan_num().bits(1);
.bits(1) w.tx_tdm_chan0_en().set_bit();
.tx_tdm_chan0_en() w.tx_tdm_chan1_en().set_bit();
.set_bit() w.tx_tdm_chan2_en().clear_bit();
.tx_tdm_chan1_en() w.tx_tdm_chan3_en().clear_bit();
.set_bit() w.tx_tdm_chan4_en().clear_bit();
.tx_tdm_chan2_en() w.tx_tdm_chan5_en().clear_bit();
.clear_bit() w.tx_tdm_chan6_en().clear_bit();
.tx_tdm_chan3_en() w.tx_tdm_chan7_en().clear_bit();
.clear_bit() w.tx_tdm_chan8_en().clear_bit();
.tx_tdm_chan4_en() w.tx_tdm_chan9_en().clear_bit();
.clear_bit() w.tx_tdm_chan10_en().clear_bit();
.tx_tdm_chan5_en() w.tx_tdm_chan11_en().clear_bit();
.clear_bit() w.tx_tdm_chan12_en().clear_bit();
.tx_tdm_chan6_en() w.tx_tdm_chan13_en().clear_bit();
.clear_bit() w.tx_tdm_chan14_en().clear_bit();
.tx_tdm_chan7_en() w.tx_tdm_chan15_en().clear_bit()
.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()
}); });
#[allow(clippy::useless_conversion)] #[allow(clippy::useless_conversion)]
i2s.rx_conf1().modify(|_, w| unsafe { i2s.rx_conf1().modify(|_, w| unsafe {
w.rx_tdm_ws_width() w.rx_tdm_ws_width()
.bits((data_format.channel_bits() - 1).into()) .bits((data_format.channel_bits() - 1).into());
.rx_bits_mod() w.rx_bits_mod().bits(data_format.data_bits() - 1);
.bits(data_format.data_bits() - 1) w.rx_tdm_chan_bits().bits(data_format.channel_bits() - 1);
.rx_tdm_chan_bits() w.rx_half_sample_bits().bits(data_format.channel_bits() - 1)
.bits(data_format.channel_bits() - 1)
.rx_half_sample_bits()
.bits(data_format.channel_bits() - 1)
}); });
#[cfg(not(esp32h2))] #[cfg(not(esp32h2))]
i2s.rx_conf1().modify(|_, w| w.rx_msb_shift().set_bit()); 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| w.rx_msb_shift().set_bit());
i2s.rx_conf().modify(|_, w| unsafe { i2s.rx_conf().modify(|_, w| unsafe {
w.rx_mono() w.rx_mono().clear_bit();
.clear_bit() w.rx_mono_fst_vld().set_bit();
.rx_mono_fst_vld() w.rx_stop_mode().bits(2);
.set_bit() w.rx_tdm_en().set_bit();
.rx_stop_mode() w.rx_pdm_en().clear_bit();
.bits(2) w.rx_pcm_bypass().set_bit();
.rx_tdm_en() w.rx_big_endian().clear_bit();
.set_bit() w.rx_bit_order().clear_bit()
.rx_pdm_en()
.clear_bit()
.rx_pcm_bypass()
.set_bit()
.rx_big_endian()
.clear_bit()
.rx_bit_order()
.clear_bit()
}); });
i2s.rx_tdm_ctrl().modify(|_, w| unsafe { i2s.rx_tdm_ctrl().modify(|_, w| unsafe {
w.rx_tdm_tot_chan_num() w.rx_tdm_tot_chan_num().bits(1);
.bits(1) w.rx_tdm_pdm_chan0_en().set_bit();
.rx_tdm_pdm_chan0_en() w.rx_tdm_pdm_chan1_en().set_bit();
.set_bit() w.rx_tdm_pdm_chan2_en().clear_bit();
.rx_tdm_pdm_chan1_en() w.rx_tdm_pdm_chan3_en().clear_bit();
.set_bit() w.rx_tdm_pdm_chan4_en().clear_bit();
.rx_tdm_pdm_chan2_en() w.rx_tdm_pdm_chan5_en().clear_bit();
.clear_bit() w.rx_tdm_pdm_chan6_en().clear_bit();
.rx_tdm_pdm_chan3_en() w.rx_tdm_pdm_chan7_en().clear_bit();
.clear_bit() w.rx_tdm_chan8_en().clear_bit();
.rx_tdm_pdm_chan4_en() w.rx_tdm_chan9_en().clear_bit();
.clear_bit() w.rx_tdm_chan10_en().clear_bit();
.rx_tdm_pdm_chan5_en() w.rx_tdm_chan11_en().clear_bit();
.clear_bit() w.rx_tdm_chan12_en().clear_bit();
.rx_tdm_pdm_chan6_en() w.rx_tdm_chan13_en().clear_bit();
.clear_bit() w.rx_tdm_chan14_en().clear_bit();
.rx_tdm_pdm_chan7_en() w.rx_tdm_chan15_en().clear_bit()
.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()
}); });
} }
@ -1762,13 +1664,19 @@ mod private {
fn reset_tx() { fn reset_tx() {
let i2s = Self::register_block(); let i2s = Self::register_block();
i2s.tx_conf() i2s.tx_conf().modify(|_, w| {
.modify(|_, w| w.tx_reset().set_bit().tx_fifo_reset().set_bit()); w.tx_reset().set_bit();
i2s.tx_conf() w.tx_fifo_reset().set_bit()
.modify(|_, w| w.tx_reset().clear_bit().tx_fifo_reset().clear_bit()); });
i2s.tx_conf().modify(|_, w| {
w.tx_reset().clear_bit();
w.tx_fifo_reset().clear_bit()
});
i2s.int_clr() i2s.int_clr().write(|w| {
.write(|w| w.tx_done().clear_bit_by_one().tx_hung().clear_bit_by_one()); w.tx_done().clear_bit_by_one();
w.tx_hung().clear_bit_by_one()
});
} }
fn tx_start() { fn tx_start() {
@ -1792,13 +1700,19 @@ mod private {
fn reset_rx() { fn reset_rx() {
let i2s = Self::register_block(); let i2s = Self::register_block();
i2s.rx_conf() i2s.rx_conf().modify(|_, w| {
.modify(|_, w| w.rx_reset().set_bit().rx_fifo_reset().set_bit()); w.rx_reset().set_bit();
i2s.rx_conf() w.rx_fifo_reset().set_bit()
.modify(|_, w| w.rx_reset().clear_bit().rx_fifo_reset().clear_bit()); });
i2s.rx_conf().modify(|_, w| {
w.rx_reset().clear_bit();
w.rx_fifo_reset().clear_bit()
});
i2s.int_clr() i2s.int_clr().write(|w| {
.write(|w| w.rx_done().clear_bit_by_one().rx_hung().clear_bit_by_one()); w.rx_done().clear_bit_by_one();
w.rx_hung().clear_bit_by_one()
});
} }
fn rx_start(len: usize) { fn rx_start(len: usize) {
@ -2060,7 +1974,7 @@ mod private {
} }
} }
#[cfg(any(esp32s3, esp32))] #[cfg(i2s1)]
impl RegBlock for I2S1 { impl RegBlock for I2S1 {
fn register_block() -> &'static RegisterBlock { fn register_block() -> &'static RegisterBlock {
unsafe { &*I2S1::PTR.cast::<RegisterBlock>() } unsafe { &*I2S1::PTR.cast::<RegisterBlock>() }
@ -2076,7 +1990,7 @@ mod private {
} }
impl super::RegisterAccess for I2S0 {} impl super::RegisterAccess for I2S0 {}
#[cfg(any(esp32s3, esp32))] #[cfg(i2s1)]
impl RegisterAccessPrivate for I2S1 { impl RegisterAccessPrivate for I2S1 {
fn set_interrupt_handler(handler: InterruptHandler) { fn set_interrupt_handler(handler: InterruptHandler) {
unsafe { crate::peripherals::I2S1::steal() }.bind_i2s1_interrupt(handler.handler()); unsafe { crate::peripherals::I2S1::steal() }.bind_i2s1_interrupt(handler.handler());
@ -2084,7 +1998,7 @@ mod private {
.unwrap(); .unwrap();
} }
} }
#[cfg(any(esp32s3, esp32))] #[cfg(i2s1)]
impl super::RegisterAccess for I2S1 {} impl super::RegisterAccess for I2S1 {}
pub trait I2s0Instance {} pub trait I2s0Instance {}
@ -2224,10 +2138,10 @@ pub mod asynch {
self.tx_chain.fill_for_tx(false, ptr, len)?; self.tx_chain.fill_for_tx(false, ptr, len)?;
future future
.tx .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(); T::tx_start();
future.await?; future.await?;
@ -2352,27 +2266,21 @@ pub mod asynch {
return Err(Error::IllegalArgument); return Err(Error::IllegalArgument);
} }
// Reset TX unit and TX FIFO // Reset RX unit and RX FIFO
T::reset_rx(); 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 { unsafe {
self.rx_chain.fill_for_rx(false, ptr, len)?; self.rx_chain.fill_for_rx(false, ptr, len)?;
future future
.rx() .rx
.prepare_transfer_without_start(T::get_dma_peripheral(), &self.rx_chain)?; .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 // start: set I2S_RX_START
#[cfg(not(esp32))]
T::rx_start(len - 1);
#[cfg(esp32)]
T::rx_start(len); T::rx_start(len);
future.await?; future.await?;
@ -2393,12 +2301,12 @@ pub mod asynch {
return Err(Error::IllegalArgument); return Err(Error::IllegalArgument);
} }
// Reset TX unit and TX FIFO // Reset RX unit and RX FIFO
T::reset_rx(); T::reset_rx();
// Enable corresponding interrupts if needed // Enable corresponding interrupts if needed
// configure DMA outlink // configure DMA inlink
unsafe { unsafe {
self.rx_chain.fill_for_rx(true, ptr, len)?; self.rx_chain.fill_for_rx(true, ptr, len)?;
self.rx_channel self.rx_channel
@ -2406,13 +2314,7 @@ pub mod asynch {
.and_then(|_| self.rx_channel.start_transfer())?; .and_then(|_| self.rx_channel.start_transfer())?;
} }
// set I2S_TX_STOP_EN if needed
// start: set I2S_RX_START // start: set I2S_RX_START
#[cfg(not(esp32))]
T::rx_start(len - 1);
#[cfg(esp32)]
T::rx_start(len); T::rx_start(len);
let state = RxCircularState::new(&mut self.rx_chain); let state = RxCircularState::new(&mut self.rx_chain);

View File

@ -59,10 +59,6 @@ harness = false
name = "i2s" name = "i2s"
harness = false harness = false
[[test]]
name = "i2s_async"
harness = false
[[test]] [[test]]
name = "lcd_cam_i8080" name = "lcd_cam_i8080"
harness = false harness = false

View File

@ -1,9 +1,10 @@
//! I2S Loopback Test //! I2S Loopback Test
//! //!
//! This test uses I2S TX to transmit known data to I2S RX (forced to slave mode //! 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 //% CHIPS: esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
//% FEATURES: generic-queue
#![no_std] #![no_std]
#![no_main] #![no_main]
@ -13,11 +14,25 @@ use esp_hal::{
dma::{Dma, DmaPriority}, dma::{Dma, DmaPriority},
dma_buffers, dma_buffers,
gpio::{Io, NoPin}, gpio::{Io, NoPin},
i2s::{DataFormat, I2s, I2sReadDma, I2sWriteDma, Standard}, i2s::{asynch::*, DataFormat, I2s, I2sReadDma, I2sTx, I2sWriteDma, Standard},
peripherals::I2S0,
prelude::*, prelude::*,
Async,
}; };
use hil_test as _; 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)] #[derive(Clone)]
struct SampleSource { struct SampleSource {
i: u8, 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)] #[cfg(test)]
#[embedded_test::tests] #[embedded_test::tests(executor = esp_hal_embassy::Executor::new())]
mod tests { 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::*; use super::*;
#[test] struct Context {
fn test_i2s_loopback() { io: Io,
dma_channel: DmaChannel0Creator,
i2s: I2S0,
}
#[init]
fn init() -> Context {
let peripherals = esp_hal::init(esp_hal::Config::default()); let peripherals = esp_hal::init(esp_hal::Config::default());
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
let delay = Delay::new();
let dma = Dma::new(peripherals.DMA); let dma = Dma::new(peripherals.DMA);
cfg_if::cfg_if! { 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( let i2s = I2s::new(
peripherals.I2S0, ctx.i2s,
Standard::Philips, Standard::Philips,
DataFormat::Data16Channel16, DataFormat::Data16Channel16,
16000.Hz(), 16000.Hz(),
dma_channel.configure(false, DmaPriority::Priority0), ctx.dma_channel
.configure_for_async(false, DmaPriority::Priority0),
rx_descriptors, rx_descriptors,
tx_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(); let din = dout.peripheral_input();
@ -96,22 +227,7 @@ mod tests {
.with_din(din) .with_din(din)
.build(); .build();
// enable loopback testing enable_loopback();
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 samples = SampleSource::new(); let mut samples = SampleSource::new();
for b in tx_buffer.iter_mut() { for b in tx_buffer.iter_mut() {
@ -121,14 +237,14 @@ mod tests {
let mut rcv = [0u8; 11000]; let mut rcv = [0u8; 11000];
let mut filler = [0x1u8; 12000]; 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 // trying to pop data before calling `available` should just do nothing
assert_eq!(0, rx_transfer.pop(&mut rcv[..100]).unwrap()); assert_eq!(0, rx_transfer.pop(&mut rcv[..100]).unwrap());
// no data available yet // no data available yet
assert_eq!(0, rx_transfer.available()); 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 iteration = 0;
let mut sample_idx = 0; let mut sample_idx = 0;
@ -180,7 +296,7 @@ mod tests {
if iteration == 1 { if iteration == 1 {
// delay to make it likely `available` will need to handle more than one // delay to make it likely `available` will need to handle more than one
// descriptor next time // descriptor next time
delay.delay_millis(160); Delay::new().delay_millis(160);
} }
} }

View File

@ -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<Self::Item> {
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;
}
}
}
}