Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I2S audio from esp32-c3 is mostly noise #1142

Closed
thedevleon opened this issue Feb 6, 2024 · 7 comments · Fixed by #1144
Closed

I2S audio from esp32-c3 is mostly noise #1142

thedevleon opened this issue Feb 6, 2024 · 7 comments · Fixed by #1144
Assignees

Comments

@thedevleon
Copy link

I'm trying to use a MAX98357A together with an ESP32-C3.

I have tried both the embassy_i2s_sound and i2s_sound samples, and while I can hear the sine wave, it is drowned in noise, with very frequent cracks and pops, and also occasionally no sound at all.

I can rule out a wiring / hardware problem, since I have no problems at all getting sound to work with arduino-audio-tools, completely noise free at 44.1kHz, and have switched between both firmwares multiple times to confirm.

To reproduce, I have setup a branch on my repo with a minimal example:
https://github.com/thedevleon/embassy-audio-on-esp/tree/broken_i2s

@thedevleon
Copy link
Author

I have a logic analyzer and an oscilloscope, so I could also look at some signals if that helps.

@bjoernQ
Copy link
Contributor

bjoernQ commented Feb 6, 2024

I notice the crackling sound with the embassy example, too. Pretty sure it wasn't always like that 🤔
But I get a perfect sine tone with the non-embassy example - even in debug mode

@bjoernQ
Copy link
Contributor

bjoernQ commented Feb 6, 2024

Mind trying this example?

//! This shows how to transmit data continuously via I2S
//!
//! Pins used
//! MCLK    GPIO4
//! BCLK    GPIO1
//! WS      GPIO2
//! DOUT    GPIO3
//!
//! Without an additional I2S sink device you can inspect the MCLK, BCLK, WS and
//! DOUT with a logic analyzer
//!
//! You can also connect e.g. a PCM510x to hear an annoying loud sine tone (full
//! scale), so turn down the volume before running this example.
//!
//! Wiring is like this
//!
//! | Pin   | Connected to    |
//! |-------|-----------------|
//! | BCK   | GPIO1           |
//! | DIN   | GPIO3           |
//! | LRCK  | GPIO2           |
//! | SCK   | Gnd             |
//! | GND   | Gnd             |
//! | VIN   | +3V3            |
//! | FLT   | Gnd             |
//! | FMT   | Gnd             |
//! | DEMP  | Gnd             |
//! | XSMT  | +3V3            |

#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]

use embassy_executor::Spawner;
use esp32c3_hal::{
    clock::ClockControl,
    dma::{Dma, DmaPriority},
    dma_buffers,
    embassy,
    i2s::{asynch::*, DataFormat, I2s, Standard},
    peripherals::Peripherals,
    prelude::*,
    IO,
};
use esp_backtrace as _;
use esp_hal::dma::DmaDescriptor;
use esp_println::println;

const SINE: [i16; 64] = [
    0, 3211, 6392, 9511, 12539, 15446, 18204, 20787, 23169, 25329, 27244, 28897, 30272, 31356,
    32137, 32609, 32767, 32609, 32137, 31356, 30272, 28897, 27244, 25329, 23169, 20787, 18204,
    15446, 12539, 9511, 6392, 3211, 0, -3211, -6392, -9511, -12539, -15446, -18204, -20787, -23169,
    -25329, -27244, -28897, -30272, -31356, -32137, -32609, -32767, -32609, -32137, -31356, -30272,
    -28897, -27244, -25329, -23169, -20787, -18204, -15446, -12539, -9511, -6392, -3211,
];

#[main]
async fn main(_spawner: Spawner) {
    #[cfg(feature = "log")]
    esp_println::logger::init_logger_from_env();
    println!("Init!");
    let peripherals = Peripherals::take();
    let system = peripherals.SYSTEM.split();
    let clocks = ClockControl::boot_defaults(system.clock_control).freeze();

    #[cfg(feature = "embassy-time-systick")]
    embassy::init(
        &clocks,
        esp32c3_hal::systimer::SystemTimer::new(peripherals.SYSTIMER),
    );

    #[cfg(feature = "embassy-time-timg0")]
    embassy::init(
        &clocks,
        esp32c3_hal::timer::TimerGroup::new(peripherals.TIMG0, &clocks),
    );

    let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);

    let dma = Dma::new(peripherals.DMA);
    let dma_channel = dma.channel0;

    let mut tx_descriptors = [DmaDescriptor::EMPTY; 20];
    let mut rx_descriptors = [DmaDescriptor::EMPTY; 8];

    let i2s = I2s::new(
        peripherals.I2S0,
        Standard::Philips,
        DataFormat::Data16Channel16,
        44100u32.Hz(),
        dma_channel.configure(
            false,
            &mut tx_descriptors,
            &mut rx_descriptors,
            DmaPriority::Priority0,
        ),
        &clocks,
    )
    .with_mclk(io.pins.gpio4);

    let i2s_tx = i2s
        .i2s_tx
        .with_bclk(io.pins.gpio1)
        .with_ws(io.pins.gpio2)
        .with_dout(io.pins.gpio3)
        .build();

    let data =
        unsafe { core::slice::from_raw_parts(&SINE as *const _ as *const u8, SINE.len() * 2) };

    let buffer = dma_buffer();
    let mut idx = 0;
    for i in 0..usize::min(data.len(), buffer.len()) {
        buffer[i] = data[idx];

        idx += 1;

        if idx >= data.len() {
            idx = 0;
        }
    }

    let mut filler = [0u8; 10000];
    let mut idx = 32000 % data.len();

    println!("Start");
    let mut transaction = i2s_tx.write_dma_circular_async(buffer).unwrap();
    loop {
        for i in 0..filler.len() {
            filler[i] = data[(idx + i) % data.len()];
        }
        println!("Next");

        let written = transaction.push(&filler).await.unwrap();
        idx = (idx + written) % data.len();
        println!("written {}", written);
    }
}

fn dma_buffer() -> &'static mut [u8; 32000] {
    static mut BUFFER: [u8; 32000] = [0u8; 32000];
    unsafe { &mut BUFFER }
}

It's basically the same just the way DMA is setup is changed back to how it was before

@bjoernQ
Copy link
Contributor

bjoernQ commented Feb 6, 2024

I guess I know what the problem is ... if the above example works for you, I probably have a real fix for it

@thedevleon
Copy link
Author

I tried running your example, but I cannot find the DmaDescriptor type in esp32c3-hal 0.15.0, I guess I will need master to run your sample?

@bjoernQ
Copy link
Contributor

bjoernQ commented Feb 6, 2024

Ah sorry for that - yes, it's not in the 0.15 release yet. If you could try it that'd awesome - if that's too cumbersome I can change it for 0.15

@thedevleon
Copy link
Author

Can confirm, in the context of master and with your changes to the embassy sample I now get a smooth sine with no noise. Nice!

I also do get the following warning though:

warning: mutable reference of mutable static is discouraged
   --> examples/embassy_i2s_sound.rs:142:14
    |
142 |     unsafe { &mut BUFFER }
    |              ^^^^^^^^^^^ mutable reference of mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
    = note: reference of mutable static is a hard error from 2024 edition
    = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
    = note: `#[warn(static_mut_ref)]` on by default
help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
    |
142 |     unsafe { addr_of_mut!(BUFFER) }
    |              ~~~~~~~~~~~~~~~~~~~~

@bjoernQ bjoernQ moved this from Todo to In Progress in esp-rs Feb 6, 2024
@bjoernQ bjoernQ self-assigned this Feb 6, 2024
@github-project-automation github-project-automation bot moved this from In Progress to Done in esp-rs Feb 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

2 participants