ESP32 C3 SUPERMINI NOISY I2S

MaikArg
Posts: 3
Joined: Sat Sep 07, 2024 3:32 am

ESP32 C3 SUPERMINI NOISY I2S

Postby MaikArg » Sat Sep 07, 2024 5:05 pm

Hi!
I'm working on a project that requires an autonomous device to record audio (44.1 kHz, 16 bits minimum).
It works well with the following hardware:
ESP32 32S, PMOD I2S2, Micro SD Card Module, Sandisk Extreme Pro. The project is not powered by any switching device, and caps are placed on all the Vcc pins for every board. The sound source is limited in voltage, so it never clips (max value is around 0.05). It works fine on a protoboard.

This setup works great, but it would be better to run it on a Super Mini C3. The pins are available, and the peripherals are sufficient.
However, I'm having issues with oscillations and noise. I'm testing just the audio loopback, and it's a bit noisy (it sounds like clipping). This is without SD card recording, just with the SPI port initialized.
Also, the data saved on the SD card is incorrect (I made a mistake when saving values).

Has anyone tried this before? I couldn't find threads about I2S and C3 Mini boards.

Also, the original code I was using on the ESP32 32S is not the same, since the driver was updated and it won't compile on de C3.


The code for the C3 is:

Code: Select all

#include "driver/i2s_std.h"
#include "driver/gpio.h"
#include <SPI.h>
#include "SdFat.h"

#define PM_MCK           GPIO_NUM_4   // PMOD Master ClocK, Limited by hardware. DO NOT CHANGE!
#define PM_WS            GPIO_NUM_3   // PMOD Word Select
#define PM_BCK           GPIO_NUM_2   // PMOD Bit ClocK
#define PM_SDIN          GPIO_NUM_1   // PMOD Serial Data IN
#define PM_SDOUT         GPIO_NUM_0   // PMOD Serial Data OUT

#define SD_CS            5   // SD Chip Select (SS)
#define SD_CLK           6   // SD Clock (SCK)
#define SD_MOSI          7   // SD Master Out Slave In (MOSI)
#define SD_MISO          8   // SD Master In Slave Out (MISO)

#define sampleRate   44100   // PMOD I2S2 sample rate.
#define BUFFER_SIZE   128   // Audio buffer size. 512, 1024, 2048, ...
// ... More variables
i2s_chan_handle_t tx_handle;
i2s_chan_handle_t rx_handle;
//... Init code
void setup_I2S() {
  i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
  i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle);
  i2s_std_config_t std_cfg = {
    .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(sampleRate),
    .slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO),
    .gpio_cfg = {
      .mclk = PM_MCK,
      .bclk = PM_BCK,
      .ws = PM_WS,
      .dout = PM_SDOUT,
      .din = PM_SDIN,
      .invert_flags = {
        .mclk_inv = false,
        .bclk_inv = false,
        .ws_inv = false,
      },
    },
  };
  i2s_channel_init_std_mode(tx_handle, &std_cfg);
  i2s_channel_init_std_mode(rx_handle, &std_cfg);
  i2s_channel_enable(tx_handle);
  i2s_channel_enable(rx_handle);
}
// ... Audio loopback. Don't pay attention to the myFile.write. Without those lines of code the loopback is still noisy.
  while (millis() < endTime) {
    i2s_channel_read(rx_handle, &rxbuf[0], 256, &readsize, 1000);
    i2s_channel_write(tx_handle, &rxbuf[0], 256, &writtesize, 1000);

    if (readsize == 256) {
      for (int i = 0; i < 128; i++) {
        l_in[i] = rxbuf[2 * i];
      }
      int written = myFile.write((byte *)l_in, BUFFER_SIZE);
      if (written == 0) {
        written = myFile.write((byte *)l_in, BUFFER_SIZE);
        if (written == 0) {
          written = myFile.write((byte *)l_in, BUFFER_SIZE);
        }
      }
    }
  }

// ... Beforo going to sleep:
  i2s_channel_disable(rx_handle);
  i2s_del_channel(rx_handle);
  i2s_channel_disable(tx_handle);
  i2s_del_channel(tx_handle);
  Serial.end();
  esp_deep_sleep_start();

lbernstone
Posts: 829
Joined: Mon Jul 22, 2019 3:20 pm

Re: ESP32 C3 SUPERMINI NOISY I2S

Postby lbernstone » Sun Sep 08, 2024 4:48 pm

I'm no audio expert, so I can't directly help you, but I have a couple questions to help illuminate the problem.
1) What are you using as the source for those clocks. You should include your code to feed those pins.
2) Do you get the noise if you use an external source for the sound? This can eliminate half the possible problems.
3) How are you physically routing? Noise and oscillations can very easily come from EMI, and those mini-c3 boards aren't exactly made to the highest of standards. If you are breadboarding, make sure the lines don't cross each other at odd angles, connected dupont wires are helpful here.

MaikArg
Posts: 3
Joined: Sat Sep 07, 2024 3:32 am

Re: ESP32 C3 SUPERMINI NOISY I2S

Postby MaikArg » Mon Sep 09, 2024 1:31 am

Thanks for the answer.

The problem was the pin definition. Pin 8 is led built in, so that was one problem.
There is other pin (didnt care about finding out witch one) so I changed all of them:

Code: Select all

#define SD_CS     GPIO_NUM_21   // SD Chip Select (SS)
#define SD_CLK    GPIO_NUM_20   // SD Clock (SCK)
#define SD_MOSI   GPIO_NUM_10   // SD Master Out Slave In (MOSI)
#define SD_MISO   GPIO_NUM_9    // SD Master In Slave Out (MISO)*/
But now I have another problem.
Can't save the data properly.
The amount of samples is ok, so datalenght is not a problem. Buffer size is OK, and works in the 32S (with the old driver).
I dont know how to define dma buffer length for the i2s peripheral.

On de 32S my I2S config was:

Code: Select all

  i2s_config_t i2s_config = {
    .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_TX),
    // i2s_mode_t work mode
    .sample_rate = sampleRate,  // int sample rate
    .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
    // i2s_bits_per_sample_t bits per sample
    .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
    // i2s_channel_fmt_t channel format
    .communication_format = I2S_COMM_FORMAT_I2S_MSB,
    // i2s_comm_format_t communication format
    .intr_alloc_flags = 0,       // int Flags used to allocate the interrupt.
    .dma_buf_count = 4,          // int DMA Buffer Count
    .dma_buf_len = 1024,         // int DMA Buffer Length
    .use_apll = true,            // bool using APLL as main clock
    .tx_desc_auto_clear = true,  // bool auto clear tx descriptor if there is underflow condition
    .fixed_mclk = true           // int using fixed MCLK output
  };
  i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
And now, with the new driver:

Code: Select all

void setup_I2S() {
  i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
  i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle);
  i2s_std_config_t std_cfg = {
    .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(sampleRate),
    .slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO),
    .gpio_cfg = {
      .mclk = PM_MCK,
      .bclk = PM_BCK,
      .ws = PM_WS,
      .dout = PM_SDOUT,
      .din = PM_SDIN,
      .invert_flags = {
        .mclk_inv = false,
        .bclk_inv = false,
        .ws_inv = false,
      },
    },
  };
  i2s_channel_init_std_mode(tx_handle, &std_cfg);
  i2s_channel_init_std_mode(rx_handle, &std_cfg);
  i2s_channel_enable(tx_handle);
  i2s_channel_enable(rx_handle);
}
And the recording function:

Code: Select all

  while (millis() < endTime) {
    i2s_channel_read( rx_handle, &rxbuf[0], BUFFER_SIZE*2,   &readsize, 1000);
    i2s_channel_write(tx_handle, &rxbuf[0], BUFFER_SIZE*2, &writtesize, 1000);
    for (int i = 0; i < BUFFER_SIZE/2; i++) {
      l_in[i] = rxbuf[2 * i];
    }
    written = myFile.write((byte *)l_in, BUFFER_SIZE);
    if (written == 0) {
      written = myFile.write((byte *)l_in, BUFFER_SIZE);
      if (written == 0) {
        written = myFile.write((byte *)l_in, BUFFER_SIZE);
      }
      if (written != BUFFER_SIZE) Serial.print("|");
    }
  }
BUFFER_SIZE, BUFFER_SIZE*2 and BUFFER_SIZE/2 are because some functions need bytes, and others are definitions. Since the data es 16 bits, the ratio between those calls is 2.

The main frequency component seems to be ok. But the signal is always clipping (even with no signal at all). Tried negating the values before recording to the sd. little endian vs big endian.
The recordings always looks like this (picture is with no signal at the input):

Image

lbernstone
Posts: 829
Joined: Mon Jul 22, 2019 3:20 pm

Re: ESP32 C3 SUPERMINI NOISY I2S

Postby lbernstone » Mon Sep 09, 2024 4:55 am

I don't have code for you; as mentioned I am not an audio expert. But, you should get best performance if you allocate 4096 (the typical flash sector size) to the dma buffer, and then use the interrupt generated from a full buffer to process the data. I think in arduino, you will have to feed the data into a queue task that will be able to save to flash.

MaikArg
Posts: 3
Joined: Sat Sep 07, 2024 3:32 am

Re: ESP32 C3 SUPERMINI NOISY I2S

Postby MaikArg » Mon Sep 09, 2024 7:01 am

Thanks for the advice lbernstone.
I'm sorry, maybe I'm not clear enough (sorry, since english is not my mother language).

Sound quality is now great. Without problems. I use audio read and audio write without problems:

Code: Select all

    i2s_channel_read( rx_handle, &rxbuf[0], BUFFER_SIZE*2,   &readsize, 1000);
    i2s_channel_write(tx_handle, &rxbuf[0], BUFFER_SIZE*2, &writtesize, 1000);
This is why I believe the driver is configured correctly.
PMOD provides and receives data as it requires. This data, when using ESP32 32S is then recorded and displayed correctly on windows trough a code in Matlab.

But now with the C3 the data recorded on the SD is totally wrong (pictures no the previous post).

ESP_Sprite
Posts: 9764
Joined: Thu Nov 26, 2015 4:08 am

Re: ESP32 C3 SUPERMINI NOISY I2S

Postby ESP_Sprite » Mon Sep 09, 2024 7:46 am

Possibly signed vs unsigned?

Who is online

Users browsing this forum: No registered users and 26 guests