Seed Studio ESP32S3 Slave I2C not working

I am having 2 esp32s3 by seed studio, I am trying to communicate between the two ESPs using I2C, so what I am trying to do is that I send data to Master ESP via BLE using NRF connect app then that data is transferred to the slave ESP but in my case what is happening is that data is getting sent successfully but the slave is not receiving it

// Master (ESP32-S3) - i2c_json_master.ino
// Sends a JSON packet over I2C to a Slave ESP32-S3

#include <Wire.h>
#include <ArduinoJson.h>

// I2C address of the Slave
#define SLAVE_ADDR 0x50

void setup() {
  Serial.begin(115200);
  // Initialize I2C as master (SDA = 21, SCL = 22 on Seed Studio ESP32-S3)
  Wire.setPins(5, 6);
  Wire.setClock(100000);
  Wire.begin();
  delay(100);
  Serial.println("I2C Master Initialized");
}

void loop() {
  // Create a JSON object
  StaticJsonDocument<200> doc;
  doc["id"] = 123;
  doc["status"] = "OK";
  doc["value"] = 50.5;

  // Serialize to string
  String json;
  serializeJson(doc, json);

  // Send JSON over I2C
  Wire.beginTransmission(SLAVE_ADDR);
  Wire.write((const uint8_t *)json.c_str(), json.length());
  byte status = Wire.endTransmission();
  if(status == 0)
  {
    Serial.println("Data Transmission Successful");
  }

  Serial.print("Sent JSON: ");
  Serial.println(json);

  delay(2000);
}

Here is my slave code

void onReceive(int bytes) {
  len = 0;
    // Serial.println("Data received");
  while (Wire.available() && len < sizeof(incoming) - 1) {
    incoming[len++] = Wire.read();
  }
  incoming[len] = '\0';
  dataReceived = true;
  // vProcessData();
  // Serial.println(incoming);
}

void setup() {
  Serial.begin(115200); /* prepare for possible serial debug */
  Serial.println("Reset Reason: " + String(esp_reset_reason()));

  if(Wire.begin(SLAVE_ADDR, I2C_SDA, I2C_SCL, FREQ))
  {
    Serial.println("I2C Initialized");
  }
  Wire.onReceive(onReceive);

  esp_task_wdt_deinit();
  vInit_Preferences();

  if (wifiStatus) {
    wm.autoConnect();
  } else if (!wifiStatus) {
    vStartWifiManager();
  }

  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("Wifi Connected");
  } else {
    Serial.println("Wifi Not Connected");
  }

  lv_xiao_touch_init();

  // mcp.begin_I2C(I2C_ADDR);

  // mcp.pinMode(WIFI_BTN, INPUT_PULLDOWN);
  // mcp.pinMode(PIR_PIN, INPUT_PULLDOWN);
  // mcp.pinMode(BTN_PIN, INPUT_PULLDOWN);

  lv_init();

  tft.begin();        /* TFT init */
  tft.setRotation(0); /* Landscape orientation, flipped */

  lv_disp_draw_buf_init(&draw_buf, buf, NULL, screenWidth * screenHeight / 10);

  /*Initialize the display*/
  static lv_disp_drv_t disp_drv;
  lv_disp_drv_init(&disp_drv);
  /*Change the following line to your display resolution*/
  disp_drv.hor_res = screenWidth;
  disp_drv.ver_res = screenHeight;
  disp_drv.flush_cb = my_disp_flush;
  disp_drv.draw_buf = &draw_buf;
  lv_disp_drv_register(&disp_drv);

  /*Initialize the (dummy) input device driver*/
  static lv_indev_drv_t indev_drv;
  lv_indev_drv_init(&indev_drv);
  indev_drv.type = LV_INDEV_TYPE_POINTER;
  indev_drv.read_cb = my_touchpad_read;
  lv_indev_drv_register(&indev_drv);


  ui_init();

}

void loop() {
  // if(Wire.available())
  if(dataReceived)
  {
    Serial.println("Data Received");
    dataReceived = false;
    vProcessData();
    memset(incoming, 0, sizeof(incoming));
  }
  
  lv_timer_handler(); /* let the GUI do its work */
  delay(5);
}

Your topic does not seem to indicate a problem with IDE 2.x and therefore has been moved to a more suitable location on the forum.

Kinda hard to help if you don't show us anything. Try adding some debug prints so we can see what is happening.

Your slave code is not complete.
It's also very hard to guess what pins you are actually using on both boards.

i am using GPIO pin 5 and 6 on both the esp32s3

this is getting printed at my slave side
17:17:43.008 -> I2C Initialized

17:17:43.008 -> First boot? YES

17:17:43.008 -> *wm:AutoConnect

17:17:43.008 -> *wm:Connecting to SAVED AP: Particle

17:17:43.248 -> *wm:connectTimeout not set, ESP waitForConnectResult...

17:17:44.079 -> *wm:AutoConnect: SUCCESS

17:17:44.079 -> *wm:STA IP Address: 192.168.0.130

17:17:44.079 -> Wifi Connected

17:17:45.113 -> lightSeedDisplay

17:17:45.113 -> 1.0.7

17:17:45.113 -> ALREADY UPDATED

17:17:45.113 -> Screen 1 :SCREEN 1

17:17:45.113 -> Screen 2 :SCREEN 2

17:17:45.113 -> Screen 4 :SCREEN 4

17:17:45.113 -> Screen 5 :SCREEN 5

17:17:45.403 -> Data Received

and this is getting printed at my master side
17:18:32.663 -> Sent JSON: {"id":123,"status":"OK","value":50.5}

17:18:34.695 -> Data Transmission Successful

17:18:34.695 -> Sent JSON: {"id":123,"status":"OK","value":50.5}

17:18:36.704 -> Data Transmission Successful

17:18:36.704 -> Sent JSON: {"id":123,"status":"OK","value":50.5}

17:18:38.698 -> Data Transmission Successful

17:18:38.698 -> Sent JSON: {"id":123,"status":"OK","value":50.5}

17:18:40.682 -> Data Transmission Successful

Update your code to include it all.
How's your wiring? Pullups?

no i dont have any pullups currently but i have tested with example code and it was working without pullups

after adding pullups too it is still the same issue

Too much confusion here..

okay soo i have created a sample code which does exactly what my real code does and i am having the very same issue with it

this is my master code

// Master: i2c_json_master.ino

#include <Wire.h>
#include <ArduinoJson.h>

#define SLAVE_ADDR 0x50

void setup() {
  Serial.begin(115200);
  Wire.begin(); // Join I2C bus as master
  delay(1000);
}

void loop() {
  // Create a JSON packet
  StaticJsonDocument<200> doc;
  doc["sensor"] = "temperature";
  doc["value"] = 24.7;
  doc["unit"] = "C";

  char buffer[200];
  size_t len = serializeJson(doc, buffer);

  // Send JSON over I2C to slave
  Wire.beginTransmission(SLAVE_ADDR);
  Wire.write((uint8_t*)buffer, len);
  Wire.endTransmission();

  Serial.println("Sent JSON to slave:");
  Serial.println(buffer);

  delay(2000);
}


THIS IS MY SLAVE CODE


#include <Wire.h>
#include <ArduinoJson.h>
#include <Adafruit_MCP23X17.h>

#define SLAVE_ADDR   0x50
#define EXPANDER_ADDR 0x27

bool flag = false;
String json;

Adafruit_MCP23X17 mcp;
void vProcessData()
{
  StaticJsonDocument<200> doc;
  DeserializationError error = deserializeJson(doc, json);
  if (error) {
    Serial.print("JSON parse failed: ");
    Serial.println(error.c_str());
    return;
  }

  // Print parsed values
  const char* sensor = doc["sensor"];
  float value = doc["value"];
  const char* unit = doc["unit"];

  Serial.print("Sensor: "); Serial.println(sensor);
  Serial.print("Value: "); Serial.print(value); Serial.print(" "); Serial.println(unit);

  // Optionally, read expander inputs
  Serial.print("Expander inputs: ");
  Serial.print(mcp.digitalRead(8)); Serial.print(",");
  Serial.print(mcp.digitalRead(9)); Serial.print(",");
  Serial.println(mcp.digitalRead(10));
}

void onReceive(int len) {
  // Read incoming JSON into buffer
  while (Wire.available()) {
    char c = Wire.read();
    json += c;
  }
  Serial.println("Received JSON:");
  Serial.println(json);
  flag = true;
  // Deserialize
}

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

  // Initialize I2C as slave
  Wire.begin(SLAVE_ADDR);
  Wire.onReceive(onReceive);

  // Initialize MCP23017 I2C expander
  mcp.begin_I2C(EXPANDER_ADDR);
  // Configure GPIO 8,9,10 as inputs (on port B: pins 8-15)
  mcp.pinMode(8, INPUT);
  mcp.pinMode(9, INPUT);
  mcp.pinMode(10, INPUT);

  Serial.println("Slave ready, MCP23017 initialized");
}

void loop() {
  // Main loop does nothing; work happens in onReceive
  if(flag)
  {
    flag = false;
    vProcessData();
  }
  delay(100);
}

If you don't specify the I2C pins, afaik wire is using 8 and 9 on Esp32-s3.

Good catch.
Anyway, it's valid only if that specific board has been defined.
For generic S3 it would point to 8 & 9.
Better approach is to define it in code.

2 Likes

Have you tried eliminating the while (Wire.available()) and reading the data into a buffer first?
Something like...

uint8_t RxData[200];

void OnReceive(int len) {
  for (int b = 0; b < len; b++) {
    RxData[b] = Wire.read();
  }
}

no this isn't working as well

Maybe it won't help but I send a 50 byte payload between two XIAO ESP32-S3's over I2C and use this code, which I know works, for testing the connection...

Controller Sender

#include <Wire.h>

uint8_t TxData[50] = { 9, 8, 7, 6, 5, 4, 3, 2, 1 };

void setup() {
  Wire.begin();
}

void loop() {
  Wire.beginTransmission(0x42);
  Wire.write(TxData, 50);
  Wire.endTransmission();

  for (int x = 0; x < 50; x++) {
    TxData[x]++;
    if (TxData[x] > 9) {
      TxData[x] = 0;
    }
  }
  delay(1000);
}

Peripheral Receiver

#include <Wire.h>

uint8_t RxData[50];
bool Received = false;

void handler(int howmany) {
  for (int i = 0; i < howmany; i++) {
    RxData[i] = Wire.read();
  }
  Received = true;
}

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

  Wire.begin(0x42, 5, 6, 100000UL);
  Wire.onReceive(handler);
}

void loop() {
  if (Received) {
    Serial.print(millis());
    Serial.print(" - ");
    for (int a = 0; a < 50; a++) {
      Serial.print(RxData[a]);
    }
    Serial.println();
    Received = false;
  }
  delay(10);
}

Just loaded and tried it and saw the expected serial output:

...
107917 - 98765432100000000000000000000000000000000000000000
108927 - 09876543211111111111111111111111111111111111111111
109927 - 10987654322222222222222222222222222222222222222222
110937 - 21098765433333333333333333333333333333333333333333
111947 - 32109876544444444444444444444444444444444444444444
112947 - 43210987655555555555555555555555555555555555555555
...

so i made some changes in mcp initialization and now my onReceive function is executing but now my main loop of the slave side isnt working
This is my master code


#include <Wire.h>
#include <ArduinoJson.h>

#define SLAVE_ADDR 0x50
 
void setup() {
  Serial.begin(115200);
  Wire.begin(D4, D5, 100000);  // Join I2C bus as master
  delay(1000);
}

void loop() {
  // Create a JSON packet
  StaticJsonDocument<200> doc;
  doc["sensor"] = "temperature";
  doc["value"] = 24.7;
  doc["unit"] = "C";

  char buffer[200];
  size_t len = serializeJson(doc, buffer);

  // Send JSON over I2C to slave
  Wire.beginTransmission(SLAVE_ADDR);
  Wire.write((uint8_t*)buffer, len);
  int status = Wire.endTransmission();

  if (status == 0) {
    Serial.println("Sent JSON to slave:");
  } else {
    Serial.println("JSON sending failed");
  }
  Serial.println(buffer);

  delay(2000);
}

and this is my slave code

#include <Wire.h>
#include <ArduinoJson.h>
#include <Adafruit_MCP23X17.h>

#define SLAVE_ADDR   0x50
#define EXPANDER_ADDR 0x27

bool flag = false;
char json[256];

Adafruit_MCP23X17 mcp;
void vProcessData()
{
  StaticJsonDocument<200> doc;
  DeserializationError error = deserializeJson(doc, json);
  if (error) {
    Serial.print("JSON parse failed: ");
    Serial.println(error.c_str());
    return;
  }

  // Print parsed values
  const char* sensor = doc["sensor"];
  float value = doc["value"];
  const char* unit = doc["unit"];

  Serial.print("Sensor: "); Serial.println(sensor);
  Serial.print("Value: "); Serial.print(value); Serial.print(" "); Serial.println(unit);

  // Optionally, read expander inputs
  Serial.print("Expander inputs: ");
  Serial.print(mcp.digitalRead(8)); Serial.print(",");
  Serial.print(mcp.digitalRead(9)); Serial.print(",");
  Serial.println(mcp.digitalRead(10));
}

void onReceive(int len) {
  // Read incoming JSON into buffer
  for(int i = 0; i < len; i++){
    json[i] = Wire.read();
    // char c = Wire.read();
    // json += c;
  }
  json[len] = '\0';
  Serial.println("Received JSON:");
  Serial.println(json);
  flag = true;
  // Deserialize
}

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

  // Initialize I2C as slave
  Wire.begin(SLAVE_ADDR,D4, D5,100000);
  Wire.onReceive(onReceive);

  // Initialize MCP23017 I2C expander
  mcp.begin_I2C(EXPANDER_ADDR, &Wire1);
  // Configure GPIO 8,9,10 as inputs (on port B: pins 8-15)
  mcp.pinMode(8, INPUT);
  mcp.pinMode(9, INPUT);
  mcp.pinMode(10, INPUT);

  Serial.println("Slave ready, MCP23017 initialized");
}

void loop() {
  // Main loop does nothing; work happens in onReceive
  Serial.println("Loop");
  if(flag)
  {
    flag = false;
    vProcessData();
  }
  delay(100);
}

"not working" and "isn't working" is not the most efficient feedback for debugging.
What happens, what's the output?
What do you get on serial monitor, if anything?
Is it successfully compiling?