Page 1 of 1

About Esp32-S3 I2S 16 channnel TDM

Posted: Fri Aug 26, 2022 8:30 am
by zh11311
Environment
Development Kit: ESP32-S3-DevKitC-1
Kit version : v1
IDF version : v4.4
Build System: idf.py
Compiler version : (crosstool-NG esp-2022r1-RC1) 11.2.0
Operating System: Windows 10
Using an IDE?: NO
Power Supply: USB

Problem Description
If I2S is configured as TDM8 Master, WS is correctly. But if I2S is configured as TDM9 to TDM16 Master, WS is not correctly.

Expected Behavior
If I2S is configured as TDM16 Master, The sample rate is configured 8000 Hz, WS output 8000 Hz.

Actual Behavior
If I2S is configured as TDM16 Master, The sample rate is configured 8000 Hz, WS output 16000 Hz.

Soure code:

#include <stdint.h>
#include <string.h>
#include <sys/time.h>
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "tinyusb.h"
#include "tusb_cdc_acm.h"
#include "sdkconfig.h"
#include "driver/i2c.h"
#include "driver/i2s.h"
#include "esp_task_wdt.h"
#include "esp_system.h"
#include "esp_check.h"


#define APP_VERSION "0.11"
#define TWDT_TIMEOUT_S 30 // task watchdog time

// TDM0
// GPIO11: TDM0_RX_MCLK
// GPIO12: TDM0_RX_BCLK
// GPIO13: TDM0_RX_LRCK
// GPIO14: TDM0_RX_DI
// GPIO17: TDM0_RX_IN

/* I2S port and GPIOs */
#define I2S_NUM (0)
#define I2S_MCK_IO (GPIO_NUM_11)
#define I2S_BCK_IO (GPIO_NUM_12)
#define I2S_WS_IO (GPIO_NUM_13)
//#define I2S_DO_IO (GPIO_NUM_14)
#define I2S_DI_IO (GPIO_NUM_14)

/* Example configurations */
#define I2S_RECV_BUF_SIZE (4000) // 4096


static const char *TAG = "GX I2S:";
static const char err_reason[][30] = {"input param is invalid",
"operation timeout"
};
static uint8_t buf[CONFIG_TINYUSB_CDC_RX_BUFSIZE + 1];

// I2S0 register address: 0x6000_F000 - 0x6000_FFFF
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_RX,
.sample_rate = 8000,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_MULTIPLE,
.communication_format = I2S_COMM_FORMAT_STAND_PCM_SHORT,
.tx_desc_auto_clear = false,
.use_apll = true,
.fixed_mclk = 4096000, //12288000,
.mclk_multiple = 256,
.dma_buf_count = 64,
.dma_buf_len = 32, // 16
.total_chan = 16, //10, //16, // 8
.chan_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1 | I2S_TDM_ACTIVE_CH2 | I2S_TDM_ACTIVE_CH3 | I2S_TDM_ACTIVE_CH4 | I2S_TDM_ACTIVE_CH5 | I2S_TDM_ACTIVE_CH6 | I2S_TDM_ACTIVE_CH7 | I2S_TDM_ACTIVE_CH8 | I2S_TDM_ACTIVE_CH9 | I2S_TDM_ACTIVE_CH10 | I2S_TDM_ACTIVE_CH11 | I2S_TDM_ACTIVE_CH12 | I2S_TDM_ACTIVE_CH13 | I2S_TDM_ACTIVE_CH14 | I2S_TDM_ACTIVE_CH15
//.total_chan = 10, //9, // 8
//.chan_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1 | I2S_TDM_ACTIVE_CH2 | I2S_TDM_ACTIVE_CH3 | I2S_TDM_ACTIVE_CH4 | I2S_TDM_ACTIVE_CH5 | I2S_TDM_ACTIVE_CH6 | I2S_TDM_ACTIVE_CH7 | I2S_TDM_ACTIVE_CH8 | I2S_TDM_ACTIVE_CH9
};

#if 1
static const i2s_pin_config_t pin_config = {
.mck_io_num = I2S_MCK_IO,
.bck_io_num = I2S_BCK_IO,
.ws_io_num = I2S_WS_IO,
.data_out_num = I2S_PIN_NO_CHANGE,
.data_in_num = I2S_DI_IO
};
#endif
int16_t *mic_data;

void tinyusb_cdc_rx_callback(int itf, cdcacm_event_t *event)
{
/* initialization */
size_t rx_size = 0;

/* read */
esp_err_t ret = tinyusb_cdcacm_read(itf, buf, CONFIG_TINYUSB_CDC_RX_BUFSIZE, &rx_size);
if (ret == ESP_OK) {
buf[rx_size] = '\0';
} else {
//ESP_LOGE(TAG, "Read error");
}

/* write back */
//tinyusb_cdcacm_write_queue(itf, buf, rx_size);
//tinyusb_cdcacm_write_flush(itf, 0);
}

void tinyusb_cdc_line_state_changed_callback(int itf, cdcacm_event_t *event)
{
int dtr = event->line_state_changed_data.dtr;
int rts = event->line_state_changed_data.rts;
ESP_LOGI(TAG, "Line state changed! dtr:%d, rts:%d", dtr, rts);
}

void app_main(void)
{
int i;
size_t bytes_read = 0;
esp_err_t ret;
uint32_t ret_num = 0;
struct timeval tv_now;
int64_t time_us, time_us1;
time_t time1, time2, time3;
uint32_t send_pkg_cnt = 0;

gettimeofday(&tv_now, NULL);
time_us = (int64_t)tv_now.tv_sec * 1000000L + (int64_t)tv_now.tv_usec;

printf("Delay for 100 milliseconds\n");
vTaskDelay(pdMS_TO_TICKS(100)); //Delay for 100 ms

ESP_ERROR_CHECK(i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL)); //install and start i2s driver
ESP_LOGI(TAG, "i2s_driver_install successfully");
ESP_ERROR_CHECK(i2s_set_pin(I2S_NUM, &pin_config));
ESP_LOGI(TAG, "i2s_set_pin successfully");

#if 1
ESP_LOGI(TAG, "USB initialization");
tinyusb_config_t tusb_cfg = {}; // the configuration using default values
ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg));

tinyusb_config_cdcacm_t amc_cfg = {
.usb_dev = TINYUSB_USBDEV_0,
.cdc_port = TINYUSB_CDC_ACM_0,
.rx_unread_buf_sz = 64, //CONFIG_TINYUSB_CDC_RX_BUFSIZE, // 64
.callback_rx = &tinyusb_cdc_rx_callback, // the first way to register a callback
.callback_rx_wanted_char = NULL,
.callback_line_state_changed = NULL,
.callback_line_coding_changed = NULL
};

ESP_ERROR_CHECK(tusb_cdc_acm_init(&amc_cfg));
/* the second way to register a callback */
ESP_ERROR_CHECK(tinyusb_cdcacm_register_callback(
TINYUSB_CDC_ACM_0,
CDC_EVENT_LINE_STATE_CHANGED,
&tinyusb_cdc_line_state_changed_callback));
ESP_LOGI(TAG, "USB initialization DONE");
#endif

unsigned int cnt = 0;
mic_data = malloc(I2S_RECV_BUF_SIZE);
if (!mic_data) {
ESP_LOGE(TAG, "[i2s_to_usb] No memory for read data buffer");
abort();
}
ret = ESP_OK;
ESP_LOGI(TAG, "Running ......");
time(&time1);
time3 = time1;
while(1) {
#if 1
//size_t bytes_read = 0;
//bytes_write = 0;
ret = i2s_read(I2S_NUM, &mic_data[0], I2S_RECV_BUF_SIZE, &bytes_read, 100);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "[i2s_to_usb] i2s read failed, %s", err_reason[ret == ESP_ERR_TIMEOUT]);
abort();
}
if(bytes_read != I2S_RECV_BUF_SIZE) {
printf("%s\n", "bytes_read != I2S_RECV_BUF_SIZE");
}
else {
send_pkg_cnt ++;
}
#endif

#if 1
tinyusb_cdcacm_write_queue(TINYUSB_CDC_ACM_0, (uint8_t *)mic_data, bytes_read); //CONFIG_TINYUSB_CDC_RX_BUFSIZE);
esp_err_t retU1;
retU1 = tinyusb_cdcacm_write_flush(TINYUSB_CDC_ACM_0, 0);
//if(retU1 != ESP_OK) {
// printf("retU1 = %d\n", retU1);
//}
#endif

time(&time2);
if(time2 - time1 >= 10) {
time1 = time2;
ESP_LOGI(TAG, "Running ......");
}
}
}