Fix I2s async-tx (#1833)
* Fix I2s async-tx * CHANGELOG.md * Add async i2s test * Cleanup * Use `Spawner::for_current_executor()` instead of manually creating the executor
This commit is contained in:
parent
c090191afb
commit
d5bff95a1b
@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix I2S async-tx (#1833)
|
||||
|
||||
### Removed
|
||||
|
||||
- This package no longer re-exports the `esp_hal_procmacros::main` macro (#1828)
|
||||
|
||||
@ -1452,7 +1452,7 @@ where
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker {
|
||||
CH::Rx::waker()
|
||||
CH::Tx::waker()
|
||||
}
|
||||
|
||||
fn is_listening_out_descriptor_error(&self) -> bool {
|
||||
|
||||
@ -52,6 +52,10 @@ harness = false
|
||||
name = "i2s"
|
||||
harness = false
|
||||
|
||||
[[test]]
|
||||
name = "i2s_async"
|
||||
harness = false
|
||||
|
||||
[[test]]
|
||||
name = "spi_full_duplex"
|
||||
harness = false
|
||||
|
||||
153
hil-test/tests/i2s_async.rs
Normal file
153
hil-test/tests/i2s_async.rs
Normal file
@ -0,0 +1,153 @@
|
||||
//! I2S Loopback Test (Async)
|
||||
//!
|
||||
//! It's assumed GPIO2 is connected to GPIO3
|
||||
//!
|
||||
//! 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 esp32s3 esp32h2
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt_rtt as _;
|
||||
use esp_backtrace as _;
|
||||
use esp_hal::{
|
||||
clock::ClockControl,
|
||||
dma::{Dma, DmaChannel0, DmaPriority},
|
||||
gpio::Io,
|
||||
i2s::{asynch::*, DataFormat, I2s, Standard},
|
||||
peripheral::Peripheral,
|
||||
peripherals::Peripherals,
|
||||
prelude::*,
|
||||
system::SystemControl,
|
||||
};
|
||||
|
||||
// choose values which DON'T restart on every descriptor buffer's start
|
||||
const ADD: u8 = 5;
|
||||
const CUT_OFF: u8 = 113;
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn writer(
|
||||
i: u8,
|
||||
mut transfer: I2sWriteDmaTransferAsync<
|
||||
'static,
|
||||
esp_hal::peripherals::I2S0,
|
||||
DmaChannel0,
|
||||
&'static mut [u8; 2000],
|
||||
>,
|
||||
) {
|
||||
let mut i = i;
|
||||
loop {
|
||||
transfer
|
||||
.push_with(|buffer| {
|
||||
for b in buffer.iter_mut() {
|
||||
*b = i;
|
||||
i = (i + ADD) % CUT_OFF;
|
||||
}
|
||||
buffer.len()
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[embedded_test::tests(executor = esp_hal_embassy::Executor::new())]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[init]
|
||||
async fn init() {}
|
||||
|
||||
#[test]
|
||||
async fn test_i2s_loopback() {
|
||||
let spawner = embassy_executor::Spawner::for_current_executor().await;
|
||||
|
||||
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;
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
let (tx_buffer, tx_descriptors, rx_buffer, rx_descriptors) =
|
||||
esp_hal::dma_circular_buffers!(2000, 2000);
|
||||
|
||||
let i2s = I2s::new(
|
||||
peripherals.I2S0,
|
||||
Standard::Philips,
|
||||
DataFormat::Data16Channel16,
|
||||
16000.Hz(),
|
||||
dma_channel.configure_for_async(false, DmaPriority::Priority0),
|
||||
tx_descriptors,
|
||||
rx_descriptors,
|
||||
&clocks,
|
||||
);
|
||||
|
||||
let 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 i2s_rx = i2s
|
||||
.i2s_rx
|
||||
.with_bclk(io.pins.gpio0)
|
||||
.with_ws(io.pins.gpio1)
|
||||
.with_din(io.pins.gpio3)
|
||||
.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 + ADD) % CUT_OFF;
|
||||
}
|
||||
|
||||
let mut rcv = [0u8; 2000];
|
||||
|
||||
let mut rx_transfer = i2s_rx.read_dma_circular_async(rx_buffer).unwrap();
|
||||
let tx_transfer = i2s_tx.write_dma_circular_async(tx_buffer).unwrap();
|
||||
|
||||
spawner.must_spawn(writer(i, tx_transfer));
|
||||
|
||||
'outer: loop {
|
||||
let len = rx_transfer.pop(&mut rcv).await.unwrap();
|
||||
for &b in &rcv[..len] {
|
||||
if b != check_i {
|
||||
failed = true;
|
||||
break 'outer;
|
||||
}
|
||||
check_i = (check_i + ADD) % CUT_OFF;
|
||||
}
|
||||
iteration += 1;
|
||||
|
||||
if iteration > 30 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert!(!failed);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user