I2S + INMP441 microphone + no_std + embassy + ESP32S3: Digital chirps on Rust esp-hal? #1596
-
First of all, thanks in advance to anybody reading this for your patience, support and expertise. Here's what I'm playing with recently: And here's the example code, it essentially reads the data from I2S0 and dumps it to the UART port: #![no_std]
#![no_main]
use embassy_executor::Spawner;
use embedded_io::Write;
use esp_backtrace as _;
use esp_hal::{
clock::ClockControl,
dma::{Dma, DmaPriority},
dma_buffers, embassy,
gpio::Io,
i2s::{asynch::I2sReadDmaAsync, DataFormat, I2s, Standard},
peripherals::Peripherals,
prelude::*,
system::SystemControl,
timer::timg::TimerGroup,
uart::{config::Config, TxRxPins, Uart},
};
// DMA buffer size
const I2S_BYTES: usize = 4096;
#[main]
async fn main(_spawner: Spawner) {
// Prepare all the peripherals and clocks
let peripherals = Peripherals::take();
let system = SystemControl::new(peripherals.SYSTEM);
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks);
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
let dma = Dma::new(peripherals.DMA);
let dma_channel = dma.channel0;
embassy::init(&clocks, timg0);
// Set DMA buffers
let (_, mut tx_descriptors, dma_rx_buffer, mut rx_descriptors) = dma_buffers!(0, I2S_BYTES * 4);
// I2S settings
let i2s = I2s::new(
peripherals.I2S0,
Standard::Philips,
DataFormat::Data16Channel16,
16000u32.Hz(),
dma_channel.configure_for_async(
false,
&mut tx_descriptors,
&mut rx_descriptors,
DmaPriority::Priority0,
),
&clocks,
);
let i2s_rx = i2s
.i2s_rx
.with_bclk(io.pins.gpio2)
.with_ws(io.pins.gpio4)
.with_din(io.pins.gpio5)
.build();
// UART settings to egress audio bytes as fast as possible (vs the ::default() 115200 baudrate)
let uart_config = Config::default().baudrate(921_600);
// On Lolin S3 1.0.0 board, UART port wired to USB2TTL IC, not OTG.
let uart_pins = Some(TxRxPins::new_tx_rx(io.pins.gpio43, io.pins.gpio44));
let uart0 = Uart::new_async_with_config(peripherals.UART0, uart_config, uart_pins, &clocks);
let (mut uart_tx, _rx) = uart0.split();
// I2S transactions to DMA buffers
let mut i2s_data = [0u8; I2S_BYTES];
let mut transaction = i2s_rx.read_dma_circular_async(dma_rx_buffer).unwrap();
loop {
let _i2s_bytes_read = transaction.pop(&mut i2s_data).await.unwrap();
uart_tx.write_all(&i2s_data).unwrap();
}
} The command line I use to dump that data is just
So to be clear, 2 and 3 represent the same audio from 1 on a loop: as pedestrian of a setup as putting the microphone close to the computer's speaker as the "Espressif" TTS is going on. Thus, comparing the last two waveforms and spectogram, you can easily tell that the data produced by the Arduino sketch replays the recorded message and the last one, produced by esp-hal snippet, is mostly digital noise. So looking at the bytes with Radare2 at an arbitrary offset in the I2S stream (representative sample), there are clearer byte-level differences between both implementations: As you can see in the Rust snippet above, I'm using the So, having established that the Arduino sketch works as intended with the hardware setup and wiring (ruling that PEBKAC out)... what am I doing wrong the the equivalent esp-hal+embassy snippet above? Could it be related with how the UART spits out the raw bytes on the wire, not respecting the raw bytes from the DMA buffer as-is? My TTY adding some major garbage to the raw data when doing that Happy to share the raw data files on request if that helps. Thanks again in advance! |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 7 replies
-
I did the same thing some time ago successfully but maybe something broke since then - needs checking |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
Amazing, thanks for your efforts @bjoernQ! I just tested your sync version and I'm having exactly the same issues, I hope it's not related to OSX USB2TTL nonsense :/ To be sure, I'll change the host (I'm doing all this on a Mac, will try with a Linux PC, hopefully tomorrow). I have a couple of followup questions before that:
PS: Also I tried to run it on my ESP32-C3 board for completeness but I have an old v0.2 of the silicon (pre-prod giveaway from your CEO), so bad luck... I wish I could apply the old linker
|
Beta Was this translation helpful? Give feedback.
Amazing, thanks for your efforts @bjoernQ!
I just tested your sync version and I'm having exactly the same issues, I hope it's not related to OSX USB2TTL nonsense :/
To be sure, I'll change the host (I'm doing all this on a Mac, will try with a Linux PC, hopefully tomorrow). I have a couple of followup questions before that:
cargo run --release
on two separate terminals? I'm running into "resource busy" issues with the serial port if I do that :-SPS: Also I tried to run i…