How to use i2s in full-duplex mode

PETER_DKID
Posts: 1
Joined: Thu Jun 01, 2023 7:17 am

Re: How to use i2s in full-duplex mode

Postby PETER_DKID » Thu Jun 01, 2023 7:54 am

Hello there. Does any one can help me please. I'm trying to do a kind of audio interface using the INMP441 microphone as input, and the MCU-5102 as output device. The idea is to do it in Real Time, with the perform of simple convolutions to make effects on output signal. But i can't do at even full-duplex comunication between components using i2s, i done it ones but with very bad quality, and since then i couldn't replicated it, and also EN pin generates some kind of error that doesn't let me go foward. This happened on projects that only involve the output of MCU-5102, as the radio wifi, it sometimes make the project fail. But thats another subject(or maybe not :/). I just want to know what im doing wrong in theory, trying to perform full-duplex comunication, and in case of convolution, should i use another buffer??. Im using ESP-32 and arduino IDE , but i didn't find a functional clue to make this work. this is my code....... Thank You so much for reading ñ_ñ.

Code: Select all

#include <driver/i2s.h>

#define SIGNAL_LENGTH 100
#define KERNEL_LENGTH 10

//INMP441
#define I2S_WS 19
#define I2S_SD 21
#define I2S_SCK 18
// Uso del procesador 0 I2S
#define I2S_INPUT_PORT I2S_NUM_0

//WCMCU
#define I2S_BCK 27
#define I2S_LCK 26
#define I2S_DIN 25
#define I2S_OUT_NC -1
#define I2S_OUTPUT_PORT I2S_NUM_1

//Constantes compartidas de definición de protocolo I2S
#define I2S_SAMPLE_RATE 44100
#define I2S_BUFFER_COUNT 8
#define BITS_PER_SAMPLE 16
#define I2S_BUFFER_LEN 128

int samplesPerBuffer =  (I2S_BUFFER_LEN / BITS_PER_SAMPLE);

int16_t inputSoundBuffer[I2S_BUFFER_LEN];
int16_t outputSoundBuffer[I2S_BUFFER_LEN];

void i2s_install() {
  // Configuración del I2S
  const i2s_config_t i2s_config = {
    .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_TX ),
    .sample_rate = I2S_SAMPLE_RATE,
    .bits_per_sample = i2s_bits_per_sample_t(16),
    .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
    // .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
  //.communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_PCM),
    .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_STAND_I2S),
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
    .dma_buf_count = I2S_BUFFER_COUNT,
    .dma_buf_len = I2S_BUFFER_LEN,
    .use_apll = false,
    .tx_desc_auto_clear = true,
    .fixed_mclk = 0
  };

  const i2s_pin_config_t pin_config_o = {
    .bck_io_num = I2S_BCK,
    .ws_io_num = I2S_LCK,
    .data_out_num = I2S_DIN,
    .data_in_num = -1
  };


   const i2s_pin_config_t pin_config_i = {
    .bck_io_num = I2S_SCK,
    .ws_io_num = I2S_WS,
    .data_out_num = -1,
    .data_in_num = I2S_SD
  };

  i2s_driver_install(I2S_INPUT_PORT, &i2s_config, 0, NULL);
  i2s_set_pin(I2S_INPUT_PORT, &pin_config_i);

  i2s_driver_install(I2S_OUTPUT_PORT, &i2s_config, 0, NULL);
  i2s_set_pin (I2S_OUTPUT_PORT, &pin_config_o);
}

void setup() {

  // Configuración del monitor serial
  Serial.begin(115200);
  Serial.println(" ");

  i2s_install();
  delay(1000);
  
  i2s_start(I2S_INPUT_PORT);
  i2s_start(I2S_OUTPUT_PORT);
}

void loop() {
    size_t bytesIn = 0;
    esp_err_t result = i2s_read(I2S_INPUT_PORT, &inputSoundBuffer, I2S_BUFFER_LEN, &bytesIn, portMAX_DELAY);

    if (result == ESP_OK)
    {

      if (bytesIn > 0) {
        for (int16_t i = 0; i < bytesIn ; i++){ //samples; ++i) {
          outputSoundBuffer[i] = (inputSoundBuffer[i]);
        }


        size_t  transBytes = bytesIn;
        i2s_write(I2S_OUTPUT_PORT, (char *) outputSoundBuffer, I2S_BUFFER_LEN, &transBytes, portMAX_DELAY);

    
      }
  }

}

eugeniomercol
Posts: 1
Joined: Sun Dec 17, 2023 9:44 am

Re: How to use i2s in full-duplex mode

Postby eugeniomercol » Sun Dec 17, 2023 10:03 am

Hi Peter!.. I have the same problem.. I just try to carry the signal from the mic INMP441 to PCM5102, and only what I got is e sand audio signal, fully of interference.. like a "Hello" -> "Shrheshllo", whit a very low volume..
What I did?.
Well, I have WemosLolinLite, INMP441, PCM5102
To make sure that everything breadboard works, I do next connections
ESP<35> -> INMP <SD>
ESP<25> -> INMP <WS> & PCM <LRC>
ESP<14> -> INMP <SCK> & PCM <BCK>
ESP<26> -> PCM <Din>

ok, I do the test for every board separately
1-
Test audio out using
ESP32-audioI2S Library - https://github.com/schreibfaul1/ESP32-audioI2S
Simple Internet Radio Demo
Config of pins exactly like in the connections note before
Result ! I have nice and clear audio out from radio host

2-
Test microfone
ESP32 I2S Microphone Sample
You can find the code here: https://dronebotworkshop.com/esp32-i2s/
calls: esp32-i2s-mic-sample.ino
Config of pins exactly like in the connections note before
Result! OK! the serial plotter shows good signal and with a high sensibility

The problem? for every test, 2 different libraries are used, and I can not to use them together, so, I did tryied with full duplex example, but, does not work.

Did you find the solution for this problem?
Do you have some example or solution to send the signal from the mic to the PCM to help me?
Thanx!

biterror
Posts: 31
Joined: Thu Apr 30, 2020 11:00 am

Re: How to use i2s in full-duplex mode

Postby biterror » Sun Dec 17, 2023 3:42 pm

Here's my i2s init code which works in 4.4.6 (full duplex):

Code: Select all

  i2s_config_t i2s_config_0 = {
    .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX),
    .sample_rate =  I2S_SAMPLE_RATE,
    .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
    .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
//    .communication_format = I2S_COMM_FORMAT_STAND_MSB,        // MSB mode doesn't work full-duplex in idf v4.2
    .communication_format = I2S_COMM_FORMAT_STAND_I2S,
    .intr_alloc_flags = 0,
    .dma_buf_count = 4, // was 8, output delay was noticeable
    .dma_buf_len = 50,  // number of samples (2x32 bit), NOT bytes!
    .use_apll = false,
    .tx_desc_auto_clear = true,
    .fixed_mclk = 0
  };
  
  i2s_pin_config_t pin_config_0 = {
    .bck_io_num = IO_SCK,       //this is BCK pin
    .ws_io_num =  IO_SPCS0,     // this is LRCK pin
    .data_out_num = IO_MOSI,    // this is DATA output pin
    .data_in_num = IO_MISO      // this is DATA input pin
  };

  i2s_driver_install(I2S_NUM_0, &i2s_config_0, 0, NULL);

  // KLUDGE: The driver works full-duplex only in Philips mode, so we
  // must change the TX mode to MSB alignment here
  WRITE_PERI_REG(I2S_CONF_REG(0), READ_PERI_REG(I2S_CONF_REG(0)) & 0xfffffbff);

  i2s_set_pin(I2S_NUM_0, &pin_config_0);
I'm using i2s for driving simple shift registers, not audio hardware, but I guess the same code should work with any external hardware as long as the i2s mode is correct.

micron
Posts: 8
Joined: Thu Nov 09, 2023 7:09 pm

Re: How to use i2s in full-duplex mode

Postby micron » Sun Dec 17, 2023 6:25 pm

I came here to ask about using I2S in full duplex vs simplex mode, and it seems that I'm not alone in my confusion.

My project is to record from a INMP441 microphone directly to an external 8M flash chip... raw writes, no file system. Then, playback the recorded audio to a MAX98357A amplifier.

I'm using esp32-s3 IDF5.1.1. For I2S I'm using the "standard" mode, not the "legacy" mode of the driver. Since I'm on a GPIO budget ( not many free pins ) I want to share the CLK and WS signals between the receiver and transmitter channels.

Following the https://docs.espressif.com/projects/esp ... on-example for full-duplex and simplex modes....

If I set up a simplex environment, then I cannot specify the same pins for CLK and WS between the rx and tx channels. If I do, then I enable just the rx channel and watch on a logic analyzer; there's no CLK or WS being output.

If I set up a duplex environment, then I can specify the same pins for CLK and WS, but unless I enable both the rx and tx channels at the same time, there's no output on CLK or WS.

Is this expected behaviour?

Who is online

Users browsing this forum: No registered users and 99 guests