Arduino NANO receiving wrong data in a simple I2C communication

Hello!

I'm testing I2C communication between an Arduino Nano and an ESP32.

I created a sketch in which I send a number and a request to the ESP32 and the ESP32 responds to the request varying from 0 or 1.

Turns out what I get from ESP32 is not the number it sent. As if there was a "delay" and it was not in sync.

What could I be doing wrong?

Here is the code and the result.

Nano:

#include <Wire.h>

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

void loop() {
  Serial.println("Sending to ESP32...");
  delay(2000);
  getInfo();
  delay(4000);
}

void getInfo() {
  int slaveAddress = 1;
  int number = 24 ;
  int check = 0;
  check = requestToSlave(slaveAddress, number);
  Serial.print("Check: ");
  Serial.println(check);
  if (check == 0) {
    int status = retrieveInfo(slaveAddress);
    Serial.print("Number received from ESP32: ");
    Serial.println(status);
  } else {
  }
};

int retrieveInfo(int slaveAddress) {
  int result = 10;
  Wire.requestFrom(slaveAddress, 1);  
  delay(100);
  while (Wire.available()) {
    result = Wire.read();  
  }
  return result;
}

int requestToSlave(int slaveAddress, int number) {
  int result = 0;
  Wire.beginTransmission(slaveAddress);
  Wire.write(number);
  delay(100);
  result = Wire.endTransmission();
  return result;
}

ESP32:

#include <Wire.h>
#define I2C_SDA 21 //A4
#define I2C_SCL 22 //A5

int numberToSend = 0;

void setup() {
  Serial.begin(38400);
  int address = 1;
  Wire.setPins(I2C_SDA, I2C_SCL);
  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvent);
  bool ok = Wire.begin(address);
  if (ok) {
    Serial.println("OK");
  }
  else {
    Serial.println("NOT OK");
  }

}

void loop() {

}

void requestEvent() {
  Serial.print("Number to send to NANO: ");
  Serial.println(numberToSend);
  delay(100);
  Wire.write(numberToSend);
}

void receiveEvent(int howMany) {
  if (Wire.available()) {
    int received = Wire.read();
    if (received > 23) {
      Serial.print("Number from NANO: ");
      Serial.println(received);
      if (numberToSend == 0) {
        numberToSend = 1;
      }
      else {
        numberToSend = 0;
      }
      Serial.print("NumberToSend: ");
      Serial.println(numberToSend);
    }
  }
}

Result:

Is the Nano a 5 or 3.3v version?
If it's the 5v version are you using a level shifter?

It's 5V. No, I'm not using a level shifter.

Please study the I2C examples carefully before writing such buggy code.

Isn't i2c a wired OR type of bus requiring pull-up resistors. The driver pulls the pin down.

A short video from Adafruit, (other brands are available)

Fix that before you do anything else. Otherwise you may destroy one or both MCUs.

1. Make setup as per following diagram using level shifter (Fig-1). If using level shifter, then there is no need to install additional pull-up resistors with the i2C Bus.


Figure-1:

2. Upload the following sketches:
Master-NANO requests Slave-ESP32 to send 0x17 in every second; Master receives the data and shows on its Serial Monitor.

I2C-Master-NANO Sketch:

#include<Wire.h>

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

void loop()
{
  Wire.requestFrom(0x23, 1);
  byte y = Wire.read();
  Serial.println(y, HEX);
  delay(1000);
}

I2C0Slave-ESP32 Sketch:

#include<Wire.h>

void setup()
{
  Serial.begin(9600);
  Wire.begin(0x23);  //default SDA = D21, SCL = D22
  //--------------
  Wire.onRequest(sendEvent);
}

void loop()
{
  
}

void sendEvent()
{
  Wire.write(0x17);
}

Master-NANO's Serial Monitor:

00:16:19.761 -> 17
00:16:20.745 -> 17
00:16:21.722 -> 17

Do you know a working project (not a simplified tutorial) that has the ESP32 as a Slave ?
This is about it: https://espressif-docs.readthedocs-hosted.com/projects/arduino-esp32/en/latest/api/i2c.html
It is not fully compatible with Arduino code.

If you really need the Nano and the ESP32 (I don't think so), then you can use Serial/UART communication (also via a level shifter).
Can you do your project with a single Arduino board ?
What is your project ? please give us a broader view.

The I2C bus is not the "bus" you think it is.

Thank you very much!

I'm using 2 ESP32s right now as I currently don't have the level shifter.

The sketch works fine, I have the same result.

However, if I modify it like this:

I2C-Master:

#include<Wire.h>
int x = 0;
void setup()
{
  Serial.begin(9600);
  Wire.begin();
}

void loop()
{
  byte y;
  Wire.requestFrom(0x23, 1);
  while (Wire.available()) {
    y = Wire.read();
  }
  Serial.println(y);
  delay(1000);
}

I2C-Slave:

#include<Wire.h>
byte t = 0;
int x = 0;
void setup()
{
  Serial.begin(9600);
  Wire.begin(0x23);  //default SDA = D21, SCL = D22
  Wire.onRequest(sendEvent);
}

void loop()
{

}

void sendEvent()
{
  Serial.println(t);
  Wire.write(t);
  t++;
}

The impression I have is that the master makes the request, the slave responds but the master only prints the value sent by the slave 1 second later, getting out of order and giving the impression that the master is "delayed".

I'm a beginner and the first time I'm having to deal with I2C communication, it may be something very obvious, but I can't see it at the moment, I apologize in advance.

Swap these statements. The first transmission may be aborted due to a timeout during Serial output, so that you get the bytes delayed by one transmission.

In I2C Communication, the following Protocol is followed:
1. As requestFrom() method is a blocking code, it stays here until requested number of data bytes arrive into its I2C Buffer from the Slave. The control automatically goes o the next line. So, there is no need to check the presence of data in the buffer.

2. The print() method requires active interrupt logic (Fig-1) for its functionality. Therefore, execute this method in the function where the interrupt logic is active, and it is the loop() function.

3. Now reload the following adjusted codes and check if there is any improvement in your perception.
Master Sketch:

#include<Wire.h>

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

void loop()
{
  Wire.requestFrom(0x23, 1);
  byte y = Wire.read();
  Serial.println(y, HEX);
  delay(1000);
}

Slave Sketch:

#include<Wire.h>
volatile bool flag = false;
volatile byte t = 0;

void setup()
{
  Serial.begin(9600);
  Wire.begin(0x23);  //default SDA = D21, SCL = D22
  //--------------
  Wire.onRequest(sendEvent);
}

void loop()
{
  if(flag == true)
  {
    Serial.println(t, HEX);
    flag = false;
  }
}

void sendEvent()
{
  Wire.write(t++);
  flag = true;
}


Figure-1:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.