I2C with different data quantities

Hi all, been working on a project where I program one arduino with 24 byte values via an interface I wrote in Processing.

This arduino is connected via I2C to three other arduini.

When arduino one receives data from processing, I would like it to send 8 of the bytes to the three slaves. Have made this work no problem.

However, most of the time, arduino one is just gathering data from analogue sensors and I would like it to blurt this information to the slaves all the time.

Have tried sending a byte at the start of the stream to tell the slave to expect either the 8 bytes from Processing or 5 bytes of general data using an if statement, but this doesn't seem to work.

Is what I'm trying to do actually possible?

Cheers! :-) Kind regards, Alex

Yes.

But some code to see what you have tried may be useful.

Are you using "End Bytes"?

Yeah, it is definitely possible, you're just doing something wrong. If you posted your code, we might even be able to tell you what!

One Arduino, three Arduini ?

The 'howMany' parameter tell show many bytes the Slave has received. However, I prefer to have a command or id byte for the first byte, that tells what kind of data it is.

Many thanks for the replies, and apologies for not posting my the code.

At the start of the transmission, I send either a 1 for general blurtings, or a 2 for sending the other data.

Here's my general blurting out data function:

void dataWriteOut(){

  Wire.beginTransmission(10); // transmit to device #10 (small turbo controller)
  byte MAPS0[] = {2, 10, 20, 30, 40, 50}; //declare an array of bytes
  Wire.write(MAPS0, 6); //send the array, stating that it contains 6 bytes
  Wire.endTransmission();    // stop transmitting

Here's what sends out the 8 bytes (actually, it's 9 bytes now!):

void mapWriteOut(){

  Wire.beginTransmission(10); // transmit to device #10 (small turbo controller)
  byte MAPS0[] = {1, v01, v02, v03, v04, v05, v06, v07, v08, maxBoostVal}; //declare an array of bytes. The '1' at the start flags that we're sending a map, not general data
  Wire.write(MAPS0, 10); //send the array, stating that it contains 10 bytes
  Wire.endTransmission();    // stop transmitting

Lastly, here's the code to receive and where I try to differentiate between the two data formats I'm receiving:

void receiveEvent(int howMany)
{
  // Read the first byte, the pointer, and the second byte, the value over the i2c bus
  incomingFlag = Wire.read();  
  if(incomingFlag == 1) {
  v01 = Wire.read();  
  v02 = Wire.read();   
  v03 = Wire.read(); 
  v04 = Wire.read();
  v05 = Wire.read();
  v06 = Wire.read();
  v07 = Wire.read();
  v08 = Wire.read();
  maxBoostVal = Wire.read();
}

  if(incomingFlag == 2){
  TPS = Wire.read();
  RPM = Wire.read();
  Sboost = Wire.read();
  Lboost = Wire.read();
  ADV = Wire.read();
  }
}

Must admit, I've no idea how the howMany variable is involved in the proceedings.

Any help much appreciated!

Kind regards, Alex

PS I may be wrong but this may be a possibility?

I can only assume the “recieveEvent(int howmany)” is called once wire.available is TRUE?

Anyway, An issue may be that you are trying to read bytes that do not exist in buffer yet…

void receiveEvent(int howMany)
{
  // Read the first byte, the pointer, and the second byte, the value over the i2c bus
  incomingFlag = Wire.read();  
  if(incomingFlag == 1) {
  v01 = Wire.read();  
  v02 = Wire.read();   
  v03 = Wire.read(); 
  v04 = Wire.read();
  v05 = Wire.read();
  v06 = Wire.read();
  v07 = Wire.read();
  v08 = Wire.read();
  maxBoostVal = Wire.read();
}

  if(incomingFlag == 2){
  TPS = Wire.read();
  RPM = Wire.read();
  Sboost = Wire.read();
  Lboost = Wire.read();
  ADV = Wire.read();
  }
}

All those wire.read() requests will happen really fast…maybe before all 10 bytes are received and stored by the I2C device?

Something more like:

while (sizeof(array_of_rx_bytes)<10){
    if (Wire.available()){
        array_of_rx_bytes[i]=Wire.read();
    i++;
    }
}

The receiveEvent() handler is an interrupt handler, it is called from an interrupt in the Wire library after all the data has been received.

The Wire.available() does not return true or false, it returns the number of bytes in the receive buffer.

That means when the function receiveEvent() is called, the 'howMany' is the same as Wire.available(). Every Wire.read() will lower the Wire.available(), but 'howMany' stays the same of course.

I prefer just a single check for 'howMany' to check if enough bytes are received and put everything in a volatile buffer. In the loop() I would take care of the meaning of that data.

Many thanks for the pointers everybody, did this to the receive code:

void receiveEvent(int howMany)
{
  // Read the first byte, the pointer, and the second byte, the value over the i2c bus
  if(howMany == 9) {
  v01 = Wire.read();  
  v02 = Wire.read();   
  v03 = Wire.read(); 
  v04 = Wire.read();
  v05 = Wire.read();
  v06 = Wire.read();
  v07 = Wire.read();
  v08 = Wire.read();
  maxBoostVal = Wire.read();
}

  if(howMany == 5){
  TPS = Wire.read();
  RPM = Wire.read();
  Sboost = Wire.read();
  Lboost = Wire.read();
  ADV = Wire.read();
  }
}

And it appears to do what I expected.

Knowing what the howMany variable does was the key to getting this working, so hope this is of use to other people too!