diff --git a/hil-test/Cargo.toml b/hil-test/Cargo.toml index d41668a69..fa3ecf12e 100644 --- a/hil-test/Cargo.toml +++ b/hil-test/Cargo.toml @@ -40,6 +40,10 @@ harness = false name = "interrupt" harness = false +[[test]] +name = "i2s" +harness = false + [[test]] name = "spi_full_duplex" harness = false diff --git a/hil-test/tests/i2s.rs b/hil-test/tests/i2s.rs new file mode 100644 index 000000000..08261fa64 --- /dev/null +++ b/hil-test/tests/i2s.rs @@ -0,0 +1,138 @@ +//! I2S Loopback Test +//! +//! It's assumed GPIO2 is connected to GPIO4 +//! +//! 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 + +//! H2 is disabled because of https://github.com/esp-rs/esp-hal/issues/1637 + +//% CHIPS: esp32c3 esp32c6 esp32s3 + +#![no_std] +#![no_main] + +use defmt_rtt as _; +use esp_backtrace as _; +use esp_hal::{ + clock::ClockControl, + dma::{Dma, DmaPriority}, + dma_buffers, + gpio::Io, + i2s::{DataFormat, I2s, I2sReadDma, I2sWriteDma, Standard}, + peripheral::Peripheral, + peripherals::Peripherals, + prelude::*, + system::SystemControl, +}; + +#[cfg(test)] +#[embedded_test::tests] +mod tests { + use super::*; + + #[init] + fn init() {} + + #[test] + fn test_i2s_loopback() { + let peripherals = Peripherals::take(); + let system = SystemControl::new(peripherals.SYSTEM); + let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + + let mut io = Io::new(peripherals.GPIO, peripherals.IO_MUX); + + let dma = Dma::new(peripherals.DMA); + let dma_channel = dma.channel0; + + let (tx_buffer, mut tx_descriptors, mut rx_buffer, mut rx_descriptors) = + dma_buffers!(32000, 32000); + + let i2s = I2s::new( + peripherals.I2S0, + Standard::Philips, + DataFormat::Data16Channel16, + 441000.Hz(), + dma_channel.configure( + false, + &mut tx_descriptors, + &mut rx_descriptors, + DmaPriority::Priority0, + ), + &clocks, + ); + + let mut i2s_tx = i2s + .i2s_tx + .with_bclk(unsafe { io.pins.gpio0.clone_unchecked() }) + .with_ws(unsafe { io.pins.gpio1.clone_unchecked() }) + .with_dout(unsafe { io.pins.gpio2.clone_unchecked() }) + .build(); + + let mut i2s_rx = i2s + .i2s_rx + .with_bclk(io.pins.gpio0) + .with_ws(io.pins.gpio1) + .with_din(io.pins.gpio4) + .build(); + + // enable loopback testing + unsafe { + let i2s = esp_hal::peripherals::I2S0::steal(); + 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().clear_bit()); + i2s.tx_conf().modify(|_, w| w.tx_update().set_bit()); + + i2s.rx_conf().modify(|_, w| w.rx_update().clear_bit()); + i2s.rx_conf().modify(|_, w| w.rx_update().set_bit()); + } + + let mut iteration = 0; + let mut failed = false; + let mut check_i: u8 = 0; + let mut i = 0; + for b in tx_buffer.iter_mut() { + *b = i; + i = i.wrapping_add(1); + } + + let mut rcv = [0u8; 5000]; + let mut filler = [0x1u8; 10000]; + + let mut rx_transfer = i2s_rx.read_dma_circular(&mut rx_buffer).unwrap(); + let mut tx_transfer = i2s_tx.write_dma_circular(&tx_buffer).unwrap(); + + 'outer: loop { + let tx_avail = tx_transfer.available(); + if tx_avail > 0 { + for b in &mut filler[0..tx_avail].iter_mut() { + *b = i; + i = i.wrapping_add(1); + } + tx_transfer.push(&filler[0..tx_avail]).unwrap(); + } + + let rx_avail = rx_transfer.available(); + if rx_avail > 0 { + rx_transfer.pop(&mut rcv[..rx_avail]).unwrap(); + for &b in &rcv[..rx_avail] { + if b != check_i { + failed = true; + break 'outer; + } + check_i = check_i.wrapping_add(1); + } + iteration += 1; + } + + if iteration > 100 { + break; + } + } + + assert!(!failed); + } +} diff --git a/hil-test/tests/interrupt.rs b/hil-test/tests/interrupt.rs index 94a41f29d..be31ada12 100644 --- a/hil-test/tests/interrupt.rs +++ b/hil-test/tests/interrupt.rs @@ -1,4 +1,6 @@ //! Interrupt Test +//! +//! "Disabled" for now - see https://github.com/esp-rs/esp-hal/pull/1635#issuecomment-2137405251 //% CHIPS: esp32c2 esp32c3 esp32c6 esp32h2 @@ -98,29 +100,30 @@ mod tests { } #[test] - fn interrupt_latency(ctx: Context) { - unsafe { - asm!( - " - csrrwi x0, 0x7e0, 1 #what to count, for cycles write 1 for instructions write 2 - csrrwi x0, 0x7e1, 0 #disable counter - csrrwi x0, 0x7e2, 0 #reset counter - " - ); - } + #[rustfmt::skip] + fn interrupt_latency(_ctx: Context) { + // unsafe { + // asm!( + // " + // csrrwi x0, 0x7e0, 1 #what to count, for cycles write 1 for instructions write 2 + // csrrwi x0, 0x7e1, 0 #disable counter + // csrrwi x0, 0x7e2, 0 #reset counter + // " + // ); + // } - // interrupt is raised from assembly for max timer granularity. - unsafe { - asm!( - " - li {bit}, 1 # Flip flag (bit 0) - csrrwi x0, 0x7e1, 1 # enable timer - sw {bit}, 0({addr}) # trigger FROM_CPU_INTR0 - ", - options(nostack), - addr = in(reg) ctx.sw0_trigger_addr, - bit = out(reg) _, - ) - } + // // interrupt is raised from assembly for max timer granularity. + // unsafe { + // asm!( + // " + // li {bit}, 1 # Flip flag (bit 0) + // csrrwi x0, 0x7e1, 1 # enable timer + // sw {bit}, 0({addr}) # trigger FROM_CPU_INTR0 + // ", + // options(nostack), + // addr = in(reg) ctx.sw0_trigger_addr, + // bit = out(reg) _, + // ) + // } } }