Skip to content

ESP32-S3 simultanous use of I2S and I2C results in racing condition #7857

@jpm1712

Description

@jpm1712

Board

ESP32-S3 DEV KIT or SUNTON 7" ESP32-S3 LCD (Makerfab)

Device Description

Problem is reproducable on both boards: ESP32-S3 DEV KIT + SUNTON 7" ESP32-S3 LCD (Makerfab). Both with external DAC MAX98573 I2S audio chip.

Hardware Configuration

No, both buses I2S (MAX98573) and I2C (GT911 LCD touch driver) are dedicated and only one device each.

Version

v2.0.6

IDE Name

PlatformIO

Operating System

Windows 11 + Linux

Flash frequency

80 MHZ

PSRAM enabled

yes

Upload speed

921600

Description

Its not possible to use both buses (I2S+I2C) together at the same time, which is defenitly useful for my SUNTON 7" ESP32-S3 device (Touch screen use + play audio sounds). Using only one of the buses in my sketch works fine. As soon as I initialize both buses, neither of them works anymore: Audio library seems to work (info output) however no sound is played. Touch screen does not work i.e. I2C outputs I2C errors. Initialising the buses in different sequence does not solve the problem. Only sequence audio works is first I2C and then I2S but then I2C does not work. I wonder weather where the problem seems to be: ESP HW bug, IDF or arduino library. Running the handlers/buses on different cores brings no solution, problem is the same.

Sketch

main.cpp:

/* This is a test file for showing simultaneously use of I2s and I2c racing condition.
External I2S DAC MAX98573 is used.
Program should run on a 7"LCD Makerfab ESP32-S3
https://wiki.makerfabs.com/Sunton_ESP32_S3_5_7_inch_IPS_with_Touch.html

You can reproduce problem with just an ESP32-S3 DEV kit and an DAC MAX98573,
because its only an audio (I2S) and I2C problem, LCD and SD SPI make no difference.

Audio Library: https://github.com/schreibfaul1/ESP32-audioI2S.git
*/

#include <Arduino.h>
#include <WiFi.h>
#include "audio.h"
#include "i2c_driver.h"

#define I2S_DOUT 17
#define I2S_BCLK 19
#define I2S_LRC 18

Audio audio;

// ------------------------------------------------
// global variables and defines used
// ------------------------------------------------
// Set your Wi-Fi Credentials here
const char *ssid = "xxxxxx";
const char *password = "xxxxxxxxxxxx";
uint last_millis = 0;

//----- Audio Function --------------------------------------------------
void audio_init()
{
  audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
  audio.setVolume(6); // 0...21
}

void audio_info(const char *info)
{
  Serial.print("info        ");
  Serial.println(info);
}
void audio_id3data(const char *info)
{ // id3 metadata
  Serial.print("id3data     ");
  Serial.println(info);
}
void audio_eof_mp3(const char *info)
{ // end of file
  Serial.print("eof_mp3     ");
  Serial.println(info);
}
void audio_showstation(const char *info)
{
  Serial.print("station     ");
  Serial.println(info);
}
void audio_showstreamtitle(const char *info)
{
  Serial.print("streamtitle ");
  Serial.println(info);
}
void audio_bitrate(const char *info)
{
  Serial.print("bitrate     ");
  Serial.println(info);
}
void audio_commercial(const char *info)
{ // duration in sec
  Serial.print("commercial  ");
  Serial.println(info);
}
void audio_icyurl(const char *info)
{ // homepage
  Serial.print("icyurl      ");
  Serial.println(info);
}
void audio_lasthost(const char *info)
{ // stream URL played
  Serial.print("lasthost    ");
  Serial.println(info);
}

void setup()
{
  Serial.begin(115200);

  // ------------------------------------------------
  // Wifi connect
  // ------------------------------------------------
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  vTaskDelay(pdMS_TO_TICKS(500));
  if (WiFi.waitForConnectResult() != WL_CONNECTED)
  {
    Serial.printf("STA: Failed!\n");
    WiFi.disconnect(false);
    vTaskDelay(pdMS_TO_TICKS(500));
    WiFi.begin(ssid, password);
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);

  i2c_driver_init();
  gt911_touch_init();

  audio_init();
  audio.connecttohost("http://vis.media-ice.musicradio.com/CapitalMP3");

  // ------------------------------------------------
  // log memory
  // ------------------------------------------------
  log_d("Total heap: %d", ESP.getHeapSize());
  log_d("Free heap: %d", ESP.getFreeHeap());
  log_d("Total PSRAM: %d", ESP.getPsramSize());
  log_d("Free PSRAM: %d", ESP.getFreePsram());

  last_millis = millis();
}

void loop()
{
  audio.loop();

  if (millis() - last_millis > 10000) // 10sec only for test, normally gt911 poll several times per second. If you make several polls per second, audio stops playing and I2C does not work at all
  {
    gt_911_handler();
    last_millis = millis();
  }
}

i2c_driver:

/* Here I make use of the esp_lcd_touch and esp_lcd_touch_gt911 in release version 090
I made my own try to use idf code for i2c and gt911 polling.

The I2S and I2C racing condition is the same problem as with use of arduino wire library and the gt911 arduino Library
https://github.com/TAMCTec/gt911-arduino.git
*/
#include <stdio.h>
#include "esp_log.h"
#include "driver/i2c.h"
#define CONFIG_LCD_HRES 800
#define CONFIG_LCD_VRES 480
#include "esp_lcd_touch.h"
#include "esp_lcd_touch_gt911.h"

static const char *TAG = "i2c-library";

#define I2C_MASTER_SCL_IO 20        /*!< GPIO number used for I2C master clock */
#define I2C_MASTER_SDA_IO 19        /*!< GPIO number used for I2C master data  */
#define I2C_MASTER_FREQ_HZ 100000   /*!< I2C master clock frequency */
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
#define WRITE_BIT I2C_MASTER_WRITE  /*!< I2C master write */
#define READ_BIT I2C_MASTER_READ    /*!< I2C master read */
#define ACK_CHECK_EN 0x1            /*!< I2C master will check ack from slave*/
#define ACK_CHECK_DIS 0x0           /*!< I2C master will not check ack from slave */

i2c_port_t i2c_master_port = 0;
esp_lcd_touch_handle_t tp;
uint16_t touch_x[1];
uint16_t touch_y[1];
uint16_t touch_strength[1];
uint8_t touch_cnt = 0;

/**
 * @brief i2c master initialization
 */
static esp_err_t i2c_master_init(void)
{
    i2c_config_t conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = I2C_MASTER_SDA_IO,
        .scl_io_num = I2C_MASTER_SCL_IO,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        conf.master.clk_speed = I2C_MASTER_FREQ_HZ,
    };

    return i2c_param_config(i2c_master_port, &conf);
}

void i2c_driver_init()
{
    i2c_driver_install(i2c_master_port, I2C_MODE_MASTER, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
    i2c_master_init();

    // scan I2C bus
    uint8_t address;
    printf("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\r\n");
    for (int i = 0; i < 128; i += 16)
    {
        printf("%02x: ", i);
        for (int j = 0; j < 16; j++)
        {
            fflush(stdout);
            address = i + j;
            i2c_cmd_handle_t cmd = i2c_cmd_link_create();
            i2c_master_start(cmd);
            i2c_master_write_byte(cmd, (address << 1) | WRITE_BIT, ACK_CHECK_EN);
            i2c_master_stop(cmd);
            esp_err_t ret = i2c_master_cmd_begin(i2c_master_port, cmd, 50 / portTICK_RATE_MS);
            i2c_cmd_link_delete(cmd);
            if (ret == ESP_OK)
            {
                printf("%02x ", address);
            }
            else if (ret == ESP_ERR_TIMEOUT)
            {
                printf("UU ");
            }
            else
            {
                printf("-- ");
            }
        }
        printf("\r\n");
        // end scan
    }
}

void gt911_touch_init()
{
    esp_lcd_touch_config_t tp_cfg = {
        .x_max = CONFIG_LCD_HRES,
        .y_max = CONFIG_LCD_VRES,
        .rst_gpio_num = GPIO_NUM_38,
        .int_gpio_num = GPIO_NUM_NC,
        .levels = {
            .reset = 1,
            .interrupt = 0,
        },
        .flags = {
            .swap_xy = 0,
            .mirror_x = 0,
            .mirror_y = 0,
        },
        .device = {.i2c = {
                       .port = i2c_master_port,
                   }}};

    esp_lcd_touch_new_i2c_gt911(&tp_cfg, &tp);
}

void gt_911_handler()
{
    esp_lcd_touch_read_data(tp);
    bool touchpad_pressed = esp_lcd_touch_get_coordinates(tp, touch_x, touch_y, touch_strength, &touch_cnt, 1);
    if (touchpad_pressed)
    {
        log_d("x: %d", touch_x[0]);
        log_d("y: %d", touch_y[0]);
    }
}

Debug Message

E (11312) GT911: touch_gt911_i2c_read(276): I2C write error!
E (11313) GT911: esp_lcd_touch_gt911_read_data(133): I2C read error!
E (22343) GT911: touch_gt911_i2c_read(276): I2C write error!
E (22343) GT911: esp_lcd_touch_gt911_read_data(133): I2C read error!

Other Steps to Reproduce

Problem seems not to be new? : Problems while running i2s and i2c at the same time. #4686
There are several issues I found describing comperable problems but they are all no solution for my problem. Either to old (2017,2018) or not the same mcu (ESP32 not ESP32-S3) etc.

I have checked existing issues, online documentation and the Troubleshooting Guide

  • I confirm I have checked existing issues, online documentation and Troubleshooting guide.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions