I2C problem - received byte does not match sent byte

I have a simple master/slave with I2C to link 2 Nanos. The problem is that the slave sends the byte 100000 but the master receives 11111111

The 2 nanos are each connected to separate laptops which provide the power through the USB connectors

The master code is

#include <Wire.h> 
byte ind_stalk_status;
long slave_poll_time = 0;
#define IND_STALK_ADDR 9

void setup(void) {
  Serial.begin(9600);
  Wire.begin();   
  Wire.setWireTimeout(3000, true);
}

void loop() {
  if (millis() - slave_poll_time > 1500) {
    slave_poll_callback();
    slave_poll_time = millis();
  }
}

void slave_poll_callback() {
  Wire.requestFrom(IND_STALK_ADDR, 1);
  byte ind_stalk_status = Wire.read(); // receive a byte
  Serial.print(F("slave_poll_callback: "));
  Serial.println(ind_stalk_status, BIN); // print the byte
}

This prints slave_poll_callback: 11111111 on each poll

Slave code

#include <Wire.h> 

void setup() {
  Serial.begin(9600);
  Wire.begin(9); 
  Wire.setWireTimeout(3000, true);
  Wire.onRequest(requestEventReceived);
}

void requestEventReceived(int bytes) {
  byte ind_status;
  bitWrite(ind_status, 5, 1);
  Serial.print(F("requestEventReceived "));
  Serial.print(F("ind_status "));
  Serial.println(ind_status, BIN);
  Serial.flush();
  Wire.write(ind_status);
}

This prints requestEventReceived ind_status 100000 on each request

That value suggests a very basic communications error. Be sure to check function return values for error status, keeping in mind that the Arduino Wire library is not very robust.

Don't you mean

  byte ind_status = 0;

Edit: You aren't sending anything to the slave.

The slave is going to send one byte,.

I assume that byte ind_status; will set the byte to 0 and the bitWrite(ind_status, 5, 1) will change the byte to 100000

Doesn’t the fact that the return is 11111111 mean that the link returned a byte?

I would not assume that. Set it to zero and see if it makes a difference.

Is the slave return the same every request?

Thanks, the print shows 100000 so the byte is being set correctly

Here is my slave

#include <Wire.h>
byte array[8] = {2,4,6,8,10,12,14,16};
volatile byte regReq = 0;
volatile byte* rtnPtr;

void setup()
{
  Wire.begin(13);
  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvent);
}

void loop()
{

}

void receiveEvent(int byteCount)
{
  regReq = Wire.read();
}

void requestEvent()
{
  rtnPtr = &array[regReq*2];

  Wire.write((byte*)rtnPtr,2);
  rtnPtr += 2;
}

Here is my master

#include <Wire.h>

void setup() {
  Serial.begin(115200);
  Wire.begin(); // join i2c bus (address optional for master)
}

byte x = 0;
int failCount = 0;

void loop() {
  Wire.beginTransmission(13); // transmit to device #13
  Wire.write(x);              // sends one byte
  if(Wire.endTransmission() != 0)
    Serial.println("Write failed");

  delayMicroseconds(10);

  if(Wire.requestFrom(13, 2) == 2) {    // request 2 bytes from slave device #13
    while(Wire.available())    // slave may send less than requested
    { 
      char c = Wire.read(); // receive a byte as character
      Serial.print(c,DEC);         // print the character
      Serial.print(" ");
    }
    Serial.print(failCount);
    Serial.println();
  }
  else {
    Serial.println(F("Fail"));
    failCount++;
  }

  x++;

  if(x > 3) x = 0;

  delay(500);
}

1. Let us say that the I2C-Master requests the I2C-Slave to send 1-byte data (0x23) at 1-sec intervals.

2. Check that your NANO-Mater and NANO-Slave are connected as per Fig-1:


Figure-1:

3. Upload the following sketches.
Master Sketch:

#include <Wire.h>
#define slaveAddr 0x09

void setup() {
  Serial.begin(9600);
  Wire.begin();
  //------------
  Wire.beginTransmission(slaveAddr);
  byte busStatus = Wire.endTransmission();
  if (busStatus != 0) {
    Serial.println("Slave is not found!");
    while (true)
      ;
  }
  Serial.println("Slave is found.");
}

void loop() {
  Wire.requestFrom(slaveAddr, 1);
  byte data = Wire.read();
  Serial.println(data, HEX);  //shows: 23
  delay(1000);
}

Slave Sketch:

#include <Wire.h>
#define slaveAddr 0x09

void setup() {
  Serial.begin(9600);
  Wire.begin(slaveAddr);
  //------------
  Wire.onRequest(sendEvent);
}

void loop() {
}

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

5. Check that SM1 (Serial Monitor 1) shows 23 at 1-sec intervals.
6. Replace 0x23 with 0xFF (11111111) and upload the Slave sketch.
7. Check that SM1 shows FF (11111111).

Thanks, the significant difference is that you are using Wire.available(), I will that a try

I don’t have resisters on the I2C lines, I will give them a try

You must need pull-up resistors on the I2C bus as the lines are open-drain.

I agree with external pullups, however doesn't Wire.begin activate internal ones?

Internal pull-up is 20k - 50k, which offers very weak pull-up!

Adding external 2x4.7 k pull-up resistors from SDA and SCL to VCC provides enough current to ensure sharp, clean voltage transitions.

I have never tried without external pullups.
Question was if internals are automatically used or lines are open-drain.

I always run the i2c_scanner sketch to check the connection.

I use 5k pullups when I use a SAMD21 as the i2c slave.

No, it just suggests that the input pullups are working on the receive end. There are several tested, functional examples of Arduino-to-Arduino communication via I2C posted on the web. Try one of those before writing your own code.

This post on Wire has helpful explanations, suggestions and warnings, e.g.

Finally, "separate laptops", if both powered from the AC line, can lead to noise problems with ground loops. Test using battery power only.

I have 5 Nanos daisy chained together for the I2C bus. I'm not hot on the electronics side but will pull up resistors be required on only one Nano as the whole line will be pulled up

Solved: Many thanks to all that helped, a pull-up resistor on the clock pin A5 did the trick. Originally I added a resistor to both A4 and A5 and the link wouldn’t work, as soon as I removed the one from A4, it started transmitting successfully

This is not a solution!

You must be placing pull-up resistors for both lines of the I2C bus as per Fig-1 of post #9 along with common GND line connected between the NANOs.

Can you confirm to me that the sketches in post #9 work for you? If they work, then that is the solution.