I2C request/response between 2 Arduino's

I am trying to get a float value calculated by one Arduino to another Arduino (the master) via I2C. I was able to do that with the help of this forum. See http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1284859119/6#6.

My second issue is that the order or request/responce is not working. I am sending a request character to my client (0x11). The client is receiving that value, but I am only getting the response back after a second full request to the client. This is the code that I am using.

Master:

#include <Wire.h>

void setup(void){
  float value = 0;

  Serial.begin(9600);
  Wire.begin();
}

char buffer[100];

void loop()
{
  union u_tag {
    byte b[4];
    float fval;
  } 
  u;
  
  int i=0;

  delay(2000);

  Wire.beginTransmission(0x05);
  Wire.send((byte)(0x11));
  
  Wire.requestFrom(0x05, 4);
   
  while(Wire.available())  
  {
    u.b[i++] = Wire.receive(); 
  } 

  Wire.endTransmission();
  
  Serial.print("Float value: ");
  Serial.println(u.fval, DEC ); 
}

Client:

#include <Wire.h>

float myValue = (float)1234.56;

byte I2C_RequestCommand = 0;

void setup() {

  Wire.begin(0x05);   
  Wire.onReceive(processI2CEvent);  
  Wire.onRequest(processRequestEvent);
  Serial.begin(9600);
}  

void loop() {
}  

void processI2CEvent(int howMany){ 
  byte I2C_command = 0;

  while (Wire.available ())
  {
    I2C_command = Wire.receive (); // receive byte as a character
  }

  if (I2C_command > 0) { // We have indeed received a valid command
    switch (I2C_command){

    case 0x11:
      Serial.println("1");
      // Store the actual request so that the onRequest handler knows
      // what to do
      I2C_RequestCommand = 0x11;
      break;

    default:
      break;
    }

    I2C_command = 0;
  }
}

void processRequestEvent(void)
{
  volatile byte* returnPtr;

  switch (I2C_RequestCommand){
    // Asume that the receiving end uses the same float representation
  case 0x11:
    Serial.println("2");
    returnPtr = (byte*) &myValue; 
    Wire.send((byte *)returnPtr,4);

    break;

  default:
    break;
  }

  I2C_RequestCommand = 0;
}

The client is using two interrupt handlers needed for the I2C stuff. The first, Wire.onReceive(processI2CEvent);, gets the command value from the master. This value is storedin I2C_RequestCommand.

The second handler Wire.onRequest(processRequestEvent); should return the float value as requested by the Wire.requestFrom(0x05, 4); of the master.

I have put two Serial.println statements in the code to see what is happening. I have checked they don't interfere with the I2C interrupts.

I would expect to see
1
2
per request. 1 comming from processI2CEvent and 2 comming from processRequestEvent.

I am getting
1

2
1

2
1

To me this looks like that the float value is only sent back after my second request. I don't see how this can happen.

Does anyone on this forum have something like this working?

Think you mixed up two different I2C communication handshakes. Try to move the endTransmission directly after the send(). NB the requestFrom is not of part of the Transmission. See Wire - Arduino Reference

...
Wire.beginTransmission(0x05);
Wire.send((byte)(0x11));
[glow]Wire.endTransmission();[/glow]  // close the transmission before requestFrom

Wire.requestFrom(0x05, 4);
while(Wire.available())  
{
  u.b[i++] = Wire.receive();
}
...

Does this help?

I thought of that too. I saw many examples where Wire.endTransmission(); was called after the send command.

I looked at this further and I am now able to get this to work correctly. The only issue is that I need a delay of about 400ms between Wire.endTransmission(); and Wire.requestFrom(0x05, 4);... I guess the client needs some time. But 400ms?

I thought of that too.

Why didn't you try it then?

The documentation of endTransmission():

Ends a transmission to a slave device that was begun by beginTransmission() and actually transmits the bytes that were queued by send().

If the sending arduino sends bytes over the wire directly after the endtransmission the receiving arduino could interpret them as being part of the transmission. So a delay seems reasonable, think you need to dive into the specs why this is ~400ms. How / where did you find this value of 400 ms?


void processI2CEvent(int howMany){

In your code you don't use the var howMany even this is very valuable information!!!

I did try, but I had no luck without the delay.

I tried several values. 400ms is approximately the shortest time that makes this would.

I am afraid you are right. It could be the queuing of the request. Well, at least I now know what is happening; I just have to code around this.

in setup() you use Serial.begin(9600);
Could you try it with 115200? and look if you stell need a 400 ms delay.

NB it could be related to the timeing of your code somehow? (just thinking out loud.

I have removed all Serial stuff from my Sketch when I tested for the 400ms delay. I must admit that the Arduino is very busy with handling external interrupts. I will try to find some time to strip the sketch in the next few days and will come back to this issue with my new findings.