Wire.read returning old data?

I am trying to set up a "keepAlive" system over IIC between two boards (Lolin D32). The process is this:
Master generates a random number (0-255)
Master saves it to an array
Master Wire.writes random number from that array to the slave
Slave immediately receives random number
Slave saves random number to its own array
delay 2 seconds----------
Master requests random number from slave
Slave sends random number directly from the array
Master saves random number into different location on its array to compare with the previous random number it sent

The problem is this:
The Slave reports that it is sending the same random number ( I have it serial print out the data from that array location before it sends it) The Master then serial prints the data that it is getting in 'live' and the numbers are not the same. The Master reports that the number it is getting is the random number generated in the previous loop.

My Questions
How is it that the old number is getting sent if the data in the array is showing as the current number and the data is being sent directly from that array position?

Is there some sort of buffer that needs to be cleared?

Additional information

  • The array stores more data than just the random number.
  • The other data in the array gets sent at the same time. The other data is not set up to change at the moment so I am unsure if that data is old as well. In other words, that data is static for now and always shows as the same thing.
  • The keepAlive() function will eventually compare the numbers in the two array locations but it doesn't do anything at the moment.
  • I am using the Wire.h lib.

Array:
Both the Slave and Master have a copy of this same array

byte commArray[6] = {240, 240, 240, 240, 0, 0};

Master:
main loop:

  sendData();
  delay(2000);
  requestData();
  delay(2000);

Functions:

void sendData() {

  int randNum = random(255);
  Serial.print("randNum = ");
  Serial.println(randNum);
  //post current random number to array pos 4
  commArray[4] = randNum;
  delay(100);
  Wire.beginTransmission(slaveAddr);
  // Send control box fan data
  Wire.write(commArray[1]);
  // Send randNum
  Wire.write(commArray[4]);
  uint8_t error = Wire.endTransmission(true);
  Serial.printf("endTransmission: %u\n", error); 
}

void requestData() {
  uint8_t bytesReceived = Wire.requestFrom(slaveAddr, 4, true);
  Serial.printf("requestFrom: %u\n", bytesReceived);
  if ((bool)bytesReceived) { //If received more than zero bytes
    uint8_t temp[bytesReceived];
    Wire.readBytes(temp, bytesReceived);
    //    log_print_buf(temp, bytesReceived);

    Serial.print("bytesReceived = ");
    Serial.println(bytesReceived);
    for (int i = 0; i < 4; i++) {
      int arrayPos;
      if (i == 0) {
        arrayPos = 0;
      } else if (i == 1) {
        arrayPos = 2;
      } else if (i == 2) {
        arrayPos = 3;
      } else if (i == 3) {
        arrayPos = 5;
      }
      commArray[arrayPos] = temp[i];
      Serial.println(temp[i]);
    }
  }// END receive

  delay(1000);
  keepAlive();
}

Slave:
Functions:

void onRequest() {
  Wire.flush();
  Serial.println("data requested !!!!!!");
  Serial.print("commArray[4] = ");
  Serial.println(commArray[4]);
  for (int i = 0; i < 4; i++) {
    int arrayPos;
    if (i == 0) {
      arrayPos = 0;
    } else if (i == 1) {
      arrayPos = 2;
    } else if (i == 2) {
      arrayPos = 3;
    } else if (i == 3) {
      arrayPos = 4;
    }
    Wire.write(commArray[arrayPos]);
    Serial.println(commArray[arrayPos]);
  }
  Serial.print("arraPos 4 = ");
  Serial.println(commArray[4]);
}

void onReceive(int len) {
  //Serial.printf("onReceive[%d]: ", len);
  // Serial.print("msg = ");
  Serial.println("Receiving...");
  while (Wire.available()) {
    int fanState = Wire.read();
    int randM = Wire.read();
    // Serial.print("fanState = ");
    // Serial.println(fanState);
    Serial.print("randM = ");
    Serial.println(randM);
    commArray[1] = fanState;
    commArray[4] = randM;
  }
    Serial.print("commArray[4] = ");
    Serial.println(commArray[4]);
    Serial.println("END Receive ----");
    Serial.println();
}

Have you checked "len"?

Have you checked "len"?

Yes, you can see that I have serial print function for that data currently commented out in the code. It shows I am receiving 2 bytes when it is uncommented. In addition, I am serial printing the incoming data itself and it is matching the random number that is generated by the Master.

The data going to the Master has no issues. The data coming from the slave back to the master is where the issue is.

Try to send back the data before logging to Serial and doing other things that may hinder proper callback operation.

Can you use Serial2 ?
The I2C is not a good bus between processors and the ESP32 Slave code is not compatible with Arduino Uno Slave code.

I remember the same discussion not long ago, and I gave the same link as below, but I can't find it anymore.

You should read this: https://espressif-docs.readthedocs-hosted.com/projects/arduino-esp32/en/latest/api/i2c.html.
But if you abandon the I2C communication between ESP32 boards, then you don't have to read that :wink:

I stripped all the serial prints from the slave when it returns the data. I did the same for the master but I am still getting old numbers....

I am not sure at this point. I have already soldered my proto boards and it looks like Serial2 uses different pins that are already in use by other things on the board.

The IIC is working, just not as expected. I would like to solve this particular issue instead of trying something else right now.

In that link you sent, it stated that Wire.write just writes to a buffer and endTransmission actually does the sending. I did not have that in my onRequest function in the slave. I am trying that now...

Did you also strip the Wire.flush()? What do you think that it should do?

Did the discussion you were trying to remember have anything to do with something like Wire.slaveWrite? According to the article it is required for esp32.

I thought that might empty the buffer of old numbers to make room for new numbers. It is not part of wire.h as far as I can tell. I took it out and nothing changed.

maybe it's not there yet? does fanState always show up correct?

How long would it take to get there? I have a 2 second delay between getting the data and then sending it back. Also, I check to see if the random numbers have been posted in the array before i send the array and they are there.

I think the issue has something to do with the buffer being sent before the new numbers are added to the buffer.

It is the lowest part of that page, with "Warning" and "for ESP32 only!".
It turns out that I can link to the bottom of that page: I2C — Arduino-ESP32 2.0.6 documentation

The way I read it, is that they forgot to design the ESP32 to be used as a I2C Slave to Arduino boards. It took a few years, but there is now a workaround, although the buffer has to to be pre-filled.

I found the other topic (it got a little nasty): https://forum.arduino.cc/t/i2c-bus-always-receiving-previously-sent-byte/1075108/8

Thanks for the reply Koepel!

I may abandon I2C as I couldn't figure out how to change the data type used in Wire.slaveWrite. It looks like it wants characters and I want to send a byte array. More specifically, only some parts of the array...

I am working on using serial2 right now. I have never used it before though and I have no idea what data types I can send using it. Wish me luck!

Wire.avail returns number of bytes ready to read, if used as a boolean then read one byte at a time, if you know you need two bytes, then wait till Wire.avail returns <1.

Like suggestion here.

The same data types that you can send with Serial. In fact, the same data types that you can send with any object whose class inherits from the Stream class.

1 Like

A little note: There is no such thing as waiting after a Wire.requestFrom(). That function is blocking. When it returns, the I2C bus session has completely finished and that was successful or not.

I prefer to check if the same number of bytes was received. The current implementation returns either zero or the same as requested, but checking for the same number looks good in the source code.


int n = Wire.requestFrom(i2c_address, 5);  // request 5 bytes
if( n == 5)  // did we get 5 bytes ?
{
  // Hooray, the same number of bytes received as was requested !
  // Read them with Wire.read() or Wire.readBytes().
  ...
}

The link that you gave to the other topic on the forum uses code taken from Github, but that code was fixed later, because of my Issue: Usage of Wire library. · Issue #3 · zharijs/FDC2214 · GitHub

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