Arduino i2c problem sending multiple bytes

I ran into a bit of a weird problem a little while back when using I2C on Arduinos.  I friend also had the problem recently so I figured maybe it was common enough that this post could help other people.  The problem occurs when you have the master request a certain number of bytes from the slave.  Except when the slave sends the bytes back, they all show up as -1 except for the last one.  Here is some example code and a workaround solution.

This wasn’t a problem I initially had since there are a couple of cases where it doesn’t present itself.  It just so happens that those two cases are the only examples I was able to find on the Arduino website.  The first example is where the master requests 6 bytes from the slave and the slave responds back with “hello “.  That’s six bytes including the space at the end so everything worked find.  The next example is where the master requests 1 byte and the slave responds with one number and everything works as it should.  The real problem is when the master requests two or more bytes and the slave sends back that number of bytes when it is not a string.  Here is example code that demonstrates this issue.

Master code:

#include <Wire.h>

void setup(){
Wire.begin() // join i2c as master
Serial.begin(9600);
}

void loop(){
Wire.requestFrom(4,2); // request 2 bytes from address 4
byte b,c;
b = Wire.read();
c = Wire.read();
Serial.print(a);
Serial.print(b);
delay(2000);
}

Slave code:

#include <Wire.h>

void setup(){
Wire.begin(4) // join i2c with address 4
// call requestEvent function when there's a request
Wire.onRequest(requestEvent);
}

void loop(){
delay(100);
}

void requestEvent() {
Wire.write(1);
Wire.write(2);
}

If you run this code and open the serial monitor port associated with the master Arduino, you should see that it will print out a weird symbol and the number 2.  That symbol that looks like an upside down caret (^ – What you get when you press shift and 6) is the ascii character for 255.  And you’ll note that 255 and -1 are the same binary (11111111).  This binary gives 255 when viewed as an unsigned int and -1 when viewed as a signed int.  So we’ve got a problem where the last byte is coming over fine but all previous bytes are getting lost.

But, if this is the case, then why does it work when you send over a string like “hello “.  Well, in C a string is really just an array of characters.  “hello ” is really just a six element array (sometimes 8 elements but that’s a story for another day) where each character is a separate element in the array.  This got me thinking – if sending an array of characters works, maybe sending an array of numbers will work as well.  So I tried with the code below.  Only the slave code is shown since the master code is unchanged from the previous example.

Slave code:

#include <Wire.h>

void setup(){
Wire.begin(4) // join i2c with address 4
// call requestEvent function when there's a request
Wire.onRequest(requestEvent);
}

void loop(){
delay(100);
}

void requestEvent() {
byte myArray[2];
myArray[0] = 1;
myArray[1] = 2;
Wire.write(myArray, 2);
}

If you run this and open up the serial monitor you should see 12 (you can add some new line print statements to the master code if you’d like to make it easier to see).  So this works perfectly and now we have a way to send multiple numbers at once by sending them as an array.

My next blog post utilizes this technique to send 16 bit and 32 bit bytes.  You can find it here.

6 thoughts on “Arduino i2c problem sending multiple bytes

  1. Hi,
    1 – I think has a typo on line 13 and 14 on master code. It must print the variables b and c, respectively.
    2 – In the codes of the site, there are errors in the conversion from special characters to html
    As >, &, <, | and so on.
    your website is very good, congratulations!

  2. I have the same problem, sending multiple single bytes does not work, but sending an array does. Thanks for the good thinking…

    1. I’m sorry you feel that way Neal. It would be helpful if you would point out the errors in the code so I can fix them. Same for the logic BS but it’s worked for other people so is there a possibility you are maybe misreading it?

  3. I think your problem in the original code is the ambiguity of the call to Wire.write. The prototype for that function does not cater for type const, which is what you are passing to it. So, it probably wants to interpret that number (1 and 2) as addresses, hence the garbage. Try defining :
    unsigned char val1=1;
    unsigned char val2=2;
    then:
    void requestEvent() {
    Wire.write(val1);
    Wire.write(val2);
    }
    Even Wire.write(‘1’) might do the trick.

    I’m reasonably certain this will solve your problem.

Leave a comment