I2C - reading two requests in sequence

Hey guys,

I'm trying to read two values from a slave device in sequence. Means, I'm doing the first request, checking the request. Regarding to the value I'm doing a second one.

If I'm doing each call with the other commented out, it works. But when I want to read them in a sequence I'm getting really weired results for the second value.

  Serial.print("read_timing_data:");
  Serial.println(slave);
  
  Wire.beginTransmission(slave);

  // TIMING AVAILABLE?
  Wire.write("TAV#");
  bool tav = false;
  if(Wire.requestFrom(slave, 1) == 1){
    tav=(bool) Wire.read();
    
    Serial.print("TAV:"); // just for debugging
    Serial.println(tav);
  }else{
    return; // no valid response
  }
  Wire.endTransmission();; // ending I2C transmission

  // GET THE TIMING
  Wire.beginTransmission(slave);
  Wire.write("LTT#");
  byte byte_data[4];
  int byte_counter = 0;
  
  unsigned long t_time = 0;
  if(Wire.requestFrom(slave, 4) == 4){
    for(int i = 0; i < 4; i++){
      byte_data[i] = Wire.read();
      //byte_counter++;

      Serial.print("BYTE: ");
      Serial.println(byte_data[i]);
    }


    t_time = byte_data[0];
    t_time = (t_time << 8) | byte_data[1];
    t_time = (t_time << 8) | byte_data[2];
    t_time = (t_time << 8) | byte_data[3];
    Serial.println(t_time);
  }
    
    Wire.endTransmission();; // ending I2C transmission

In the second request, I'm receiving the wrong bytes although the correct ones are getting send by the slave. Like, I wrote. If I comment one of the requests out, it works. But two of them together it doesn't. Any clue why this happens?

Here's also the small func of the slave responsible for sending the data:

void i2c_on_request(){
  if(wire_request_mode == WRM_TAV){
     Wire.write(last_tracked_time_available);
  }

  if(wire_request_mode == WRM_LTT){
    //Wire.write(last_tracked_time);
    byte myArray[4];
    last_tracked_time = 666;
    myArray[0] = (last_tracked_time >> 24) & 0xFF;
    myArray[1] = (last_tracked_time >> 16) & 0xFF;
    myArray[2] = (last_tracked_time >> 8) & 0xFF;
    myArray[3] = last_tracked_time & 0xFF;
 
    Wire.write(myArray, 4);

    last_tracked_time = 0;
    last_tracked_time_available = false;

    /*for(int i = 0; i < 4; i++){
      Serial.print("BYTE: ");
      Serial.println(myArray[i]);
    }*/
  }

  wire_request_mode = WRM_NONE;
}

The results I'm receving and sending:

CLIENT-Bytes:
BYTE: 0
BYTE: 0
BYTE: 2
BYTE: 154
Number: 666

MASTER-Bytes:
BYTE: 3
BYTE: 0
BYTE: 2
BYTE: 154
Number: 50332314

Where does this number 3 comes from the first byte in the master? oO

It is the endTransmission call that sends the data. If you call requestFrom before that, it hasn't received your data yet.

Hm,

I've changed it to this code:

// GET THE TIMING
  Wire.beginTransmission(slave);
  Wire.write("LTT#");
  Wire.endTransmission();; // ending I2C transmission
  byte byte_data[4];
  int byte_counter = 0;
  
  unsigned long t_time = 0;
  if(Wire.requestFrom(slave, 4) == 4){
    for(int i = 0; i < 4; i++){
      byte_data[i] = Wire.read();
      //byte_counter++;

      Serial.print("BYTE: ");
      Serial.println(byte_data[i]);
    }


    t_time = byte_data[0];
    t_time = (t_time << 8) | byte_data[1];
    t_time = (t_time << 8) | byte_data[2];
    t_time = (t_time << 8) | byte_data[3];
    Serial.println(t_time);
  }

so that the end transmission is finished.

But I'm still having the first byte wrong:

BYTE: 3
BYTE: 0
BYTE: 255
BYTE: 255

You must know, I'm just sending the slave a cmd so that he knows next time, when I'm requesting something, I want a special value. The value which gets send by the slave to master is the problem. In the slave, the correct bytes are getting sent but the master simply has the wrong first byte. It should be zero instead of 3 in the above example.

Is last_tracked_time a long or unsigned long? Maybe if you posted your code for the master and slave, I can test it.

I have test i2c code for a master and slave if you are interested.

Thanks for your help man. I've found the problem! After each endTransmission, I had to put a small delay, 10ms and it works. Looks like the two Nanos need some time to synchronize.

I use a delayMicroseconds(100) and that does the trick.

edit: Of course the longer it takes to prepare the reply, the longer the delay should be.

With the bug fixes of the Wire library in Arduino IDE 1.6.6, I don't need a delay anymore. But that depends on the code of the Slave. If you show the code of the Slave, we can have a look at it.
I assume that clock pulse stretching by the Slave is enough to return valid data all the time.

I'm using IDE v1.6.9, and I need a delay, or I get occasional fails. For this code, 100us is enough to never get a fail. Do you see anything wrong with my code?

Here is my slave code.

#include <Wire.h>
byte array[8] = {2,4,6,8,10,12,14,16};
volatile byte regReq = 0;
volatile byte* rtnPtr;
 
void setup()
{
//  Serial.begin(115200);
  Wire.begin(13);
  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvent);
}

void loop()
{

}

void receiveEvent(int byteCount)
{
  regReq = Wire.read();
  rtnPtr = &array[regReq*2];    
}

void requestEvent()
{
  Wire.write((byte*)rtnPtr,2);
}

Here is my master code.

#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
  Wire.endTransmission();    // stop transmitting

  delayMicroseconds(100);
  
  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);
}

I have a project with that and I have removed that delay. So far without any problems. I do keep track of those errors. The Slaves for that projects are 16MHz 5V and 8MHz 3.3V Slaves (with I2C level shifter). I have of course updated all the sketches for all the Slaves and the Master. It works at I2C speed of 400kHz, but I have choosen 200kHz for safety.
Before version 1.6.6, I got continuesly errors without the delay.

Test: Two Arduino Uno boards, both connected to the computer and between them wires : GND, SDA, SCL. No pullup resistors. Using your example sketches. Arduino IDE 1.6.9.

With delay of 100 us : no fail during 5 minutes.
Without delay : no fail during 5 minutes.
Without delay and with repeated start, using parameter 'false' for endTransmission : no fail during 5 minutes

Tell me what to do to get a fail :o

I ran mine for about the last hour with the delay without a single fail.

I ran mine 5 minutes without the delay. If you look at my code, the third number is the number of fails.

2 4 8
6 8 8
10 12 8
14 16 8

edit: Master is a Due (3.3v) and the slave is a Mega 2560 (5v) with an Adafruit logic level converter between them. It's been 10 minutes and I'm up to 15 fails.

I'm still running without the delay for 30 minutes (but not the repeated start), so far no error.
Both my project and this test have no errors.

Are you sure that both the Master and the Slave use Arduino IDE 1.6.9 ?
Do you use two ATmega328P chips ? Or newer processors with a Wire library that still has bugs ?
Have you made changes to the Wire library ?
Do you use an alternative Wire library with timeouts ?

No changes to the Wire library here. I'm using the standard wire library on both boards. The Due is a SAM IC.

I'm approaching 20 minutes and have accumulated 26 fails.

I might try an experiment. I'll make the Mega the master and the Due the slave and see if that makes a difference.

Well, it must be the Due as the master that causes the fails. Maybe the Due's 84MHz IC is outrunning the mega when set as the master. It's been 5 minutes with no fail.

@SurferTim, the fixes for the Wire library with version 1.6.6 are for the ATmega family Wire library. The problem is the Due Wire library, and not a speed issue of the processor. I don't have a Due, so I can't test it.
I assume you have a level shifter between your two Arduino boards ? or else you are working outside the specifications.

@TheBino, You have two Nano boards, so you have two ATmega328P chips. I have checked carefully every Slave for disabling the interrupts and other interrupts. Perhaps one of your Slaves is running code that needs to be fixed. Although a little extra delay in the Master is not a big problem. You use 10ms, that is a big delay. Would 1ms be enough ? Or are you not using the Arduino IDE 1.6.9 ?

I don't run stuff outside specs. I mentioned the logic level converter in reply #9.

It's been almost 15 minutes without a fail with the Due as the slave. Is the i2c problem only with the master code?

edit: I'm beginning to doubt the bug hypothesis. I'm back with the Due as the master and the Mega as the slave. I've reduced the delay to 10us for a test. If this is a bug, why would a short delay correct it?

@SurferTim, you did mention the level converter, sorry. I assume that the Due Wire library has a bug for the Master. I have read about problems before, but I can't find it at the moment. When the Due Wire library was introduced, it was not even compatible with the documention.

This is not uncommon, for example the Wire library for the ESP8266 seems to be even less compatible.

If this is a bug, why does a short delay between the endTransmission and the requestFrom correct it?

I don't know. I don't understand the source code and the I2C hardware. This happened to the ATmega Wire library (before 1.6.6) as well, and the fix is too hard to understand for me. Perhaps checking an extra bit to test if the I2C transaction did really end, but at the same time there were also fixes for testing for collisions.

I'm down to 10us on the delay and it is working. Any less than that and I start picking up fails. I'm ok with a 10us delay.

I appreciate the info though. It could be a collision with the slave thing. Maybe the Due's master code does not check to see if the SCK and SDA lines are HIGH before starting another send.

We could be on to something.
It was 6us in my project with the old ATmega Wire libary. Since the Due is faster, the 10us could be the same issue. At 100kHz a clock length is 10us.