espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.35k stars 7.21k forks source link

I2S full duplex 32 bit issue (IDFGH-7563) #9123

Open SimonPVS opened 2 years ago

SimonPVS commented 2 years ago

Environment

Problem Description

I am trying to use i2s with 32 bits per sample at a sample rate of 48kHz. But this does not seem to work. I am using the esp-idf i2s full duplex example. With 16 bits per sample it works but when switching to 32 bits per sample, it doesn't.

My config:

static void initI2s1() {
  i2s_config_t i2s_config = {
      .mode = I2S_MODE_SLAVE | I2S_MODE_TX | I2S_MODE_RX,
      .sample_rate = SAMPLE_RATE,
      .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
      .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
      .communication_format = I2S_COMM_FORMAT_STAND_I2S,
      .dma_buf_count = 10,
      .dma_buf_len = 1024,
      .use_apll = true,
      .mclk_multiple = EXAMPLE_MCLK_MULTIPLE,
      .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1  // Interrupt level 1
  };
  i2s_pin_config_t pin_config = {
      .mck_io_num = GPIO_NUM_0,  // I2S_PIN_NO_CHANGE,
      .bck_io_num = GPIO_NUM_5,
      .ws_io_num = GPIO_NUM_32,
      .data_out_num = GPIO_NUM_16,
      .data_in_num = GPIO_NUM_34};

  i2s_driver_install(0, &i2s_config, 0, NULL);
  i2s_set_pin(0, &pin_config);
}

Expected Behavior

32 bit i2s

Actual Behavior

No i2s output

Code to reproduce this issue

#include <math.h>
#include <stdio.h>
#include <string.h>

#include "driver/gpio.h"
#include "driver/i2s.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#define SAMPLE_RATE (48000)

#define EXAMPLE_MCLK_MULTIPLE I2S_MCLK_MULTIPLE_256

static const char* TAG = "i2s_example";
static const char err_reason[][30] = {"input param is invalid",
                                      "operation timeout"};

static void i2s_echo(void* args) {
  int* mic_data = malloc(8192);
  if (!mic_data) {
    ESP_LOGE(TAG, "[echo] No memory for read data buffer");
    abort();
  }
  esp_err_t ret = ESP_OK;
  size_t bytes_read = 0;
  size_t bytes_write = 0;
  ESP_LOGI(TAG, "[echo] Echo start");

  while (1) {
    memset(mic_data, 0, 8192);
    /* Read sample data from mic */
    ret = i2s_read(0, mic_data, 8192, &bytes_read, 100);
    if (ret != ESP_OK) {
      ESP_LOGE(TAG, "[echo] i2s read failed, %s",
               err_reason[ret == ESP_ERR_TIMEOUT]);
      abort();
    }

    /* Write sample data to earphone */
    ret = i2s_write(0, mic_data, 8192, &bytes_write, 100);
    if (ret != ESP_OK) {
      ESP_LOGE(TAG, "[echo] i2s write failed, %s",
               err_reason[ret == ESP_ERR_TIMEOUT]);
      abort();
    }
    if (bytes_read != bytes_write) {
      ESP_LOGW(TAG, "[echo] %d bytes read but only %d bytes are written",
               bytes_read, bytes_write);
    }
  }
  vTaskDelete(NULL);
}

static void i2s2_echo(void* args) {
  int* mic_data = malloc(4096);
  if (!mic_data) {
    ESP_LOGE(TAG, "[echo] No memory for read data buffer");
    abort();
  }
  esp_err_t ret = ESP_OK;
  size_t bytes_read = 0;
  size_t bytes_write = 0;
  ESP_LOGI(TAG, "[echo] Echo start");

  while (1) {
    memset(mic_data, 0, 4096);
    /* Read sample data from mic */
    ret = i2s_read(1, mic_data, 4096, &bytes_read, 100);
    if (ret != ESP_OK) {
      ESP_LOGE(TAG, "[echo] i2s read failed, %s",
               err_reason[ret == ESP_ERR_TIMEOUT]);
      abort();
    }

    /* Write sample data to earphone */
    ret = i2s_write(1, mic_data, 4096, &bytes_write, 100);
    if (ret != ESP_OK) {
      ESP_LOGE(TAG, "[echo] i2s write failed, %s",
               err_reason[ret == ESP_ERR_TIMEOUT]);
      abort();
    }
    if (bytes_read != bytes_write) {
      ESP_LOGW(TAG, "[echo] %d bytes read but only %d bytes are written",
               bytes_read, bytes_write);
    }
  }
  vTaskDelete(NULL);
}

static void initI2s1() {
  i2s_config_t i2s_config = {
      .mode = I2S_MODE_SLAVE | I2S_MODE_TX | I2S_MODE_RX,
      .sample_rate = SAMPLE_RATE,
      .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
      .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
      .communication_format = I2S_COMM_FORMAT_STAND_I2S,
      .dma_buf_count = 10,
      .dma_buf_len = 1024,
      .use_apll = true,
      .mclk_multiple = EXAMPLE_MCLK_MULTIPLE,
      .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1  // Interrupt level 1
  };
  i2s_pin_config_t pin_config = {
      .mck_io_num = GPIO_NUM_0,  // I2S_PIN_NO_CHANGE,
      .bck_io_num = GPIO_NUM_5,
      .ws_io_num = GPIO_NUM_32,
      .data_out_num = GPIO_NUM_16,
      .data_in_num = GPIO_NUM_34};

  i2s_driver_install(0, &i2s_config, 0, NULL);
  i2s_set_pin(0, &pin_config);
}

static void initI2s2() {
  i2s_config_t i2s_config = {
      .mode = I2S_MODE_SLAVE | I2S_MODE_TX | I2S_MODE_RX,
      .sample_rate = SAMPLE_RATE,
      .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
      .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
      .communication_format = I2S_COMM_FORMAT_STAND_I2S,
      .dma_buf_count = 6,
      .dma_buf_len = 60,
      .use_apll = false,
      .mclk_multiple = EXAMPLE_MCLK_MULTIPLE,
      .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1  // Interrupt level 1
  };
  i2s_pin_config_t pin_config = {.mck_io_num = GPIO_NUM_0,
                                 .bck_io_num = GPIO_NUM_16,  // 16
                                 .ws_io_num = GPIO_NUM_15,   // 15
                                 .data_out_num = GPIO_NUM_14,
                                 .data_in_num = GPIO_NUM_13};
  i2s_driver_install(1, &i2s_config, 0, NULL);
  i2s_set_pin(1, &pin_config);
}

void app_main(void) {
  initI2s1();
  xTaskCreate(i2s_echo, "i2s1_echo", 8192, NULL, 5, NULL);

  // initI2s2();
  // xTaskCreate(i2s2_echo, "i2s2_echo", 8192, NULL, 5, NULL);

  while (1) {
    vTaskDelay(50000 / portTICK_PERIOD_MS);
  }
}
L-KAYA commented 2 years ago

Actually, the hardware of I2S on ESP32 does not supported slave mode pretty well, 48 KHz sample rate is too high for slave mode with 32bit to catch the clock, you may need to lower down the sample rate.

SimonPVS commented 2 years ago

I have managed to make it work recently. But I need to do more tests to know if it is stable. I do not use the MCLK input anymore but i am using a fixed I2S MCLK clock now (25MHz).

I am not sure that tis will be a good sollution because the master and slave MCLKs are not the same now (still have to see if this will give any issues)

mrshankar commented 1 year ago

@SimonPVS , Could you please explain how did it work for you , i am still struggling , ESP32 as I2S SLAVE |TX mode

heartwerker commented 1 year ago

I am also struggling to setup standard ESP32 to I2S Slave TX mode

A bit different but maybe related ... my problem is better described in this esp-forum issue: --> I2S: Samples incorrectly zeroed when I2S interface is in slave mode

@SimonPVS or others would love to see what worked for you ..

grateful for any input here!