Go Down

Topic: i2c questions - sending multiple bytes to and from arduinos (Read 24042 times) previous topic - next topic

Aryl

I've been reading about i2c and thought it sounded like a nice solution for communication between arduinos. I've got two set up and communicating to each other, but I've got a few questions.

It works, but I don't understand how or why.

I've read that wire.write() sends one byte at a time, and that it is the master's job to receive the data and reconstruct it into the appropriate format. They also have to agree on the data structure being sent to do this.


Simply trying

Code: [Select]
wire.write(w)

(With w being an unsigned int) and then receiving it on the master with

Code: [Select]
int x = Wire.read

results in two lines being printed to the serial monitor, even when I used Serial.print(x) and not Serial.println. It looked like it was printing the first byte, then reading x into the second byte and overwriting the first, printing the value of x in between overwriting it.

I played with it for a few hours before finding that this works:

Slave:

Code: [Select]
Wire.write((byte *)&w, sizeof(unsigned int));

Master:

Code: [Select]

Wire.requestFrom(2, 2);     // request 2 bytes from slave device #2

   while(Wire.available())    // slave may send less than requested
  {
     x = Wire.read();         
     y = Wire.read();         
     z = y * 256 + x;         


Question being, although this works great, what exactly is going on here?

I'm guessing that the single line of code on the slave device sends the two bytes to the master (Defined by sizeof() ?). It somehow knows to send one byte the first Wire.read, and the second byte on the second Wire.read (Is this a parameter that must be given, or does it always do this? If I were to send an unsigned long, would it send out the 4 bytes through the master reading 4 times in a row? Surely there must be come kind of confirmation by the master that it's read byte 1 out of 4, send the next one on the next read please?)

The master then reads the first byte sent into x, then reads again and is sent the second byte which it reads into y, and somehow combines them into the original 2-byte int with z = y * 256 + x (Some kind of bitshifting magic?).

Could somebody kindly walk me through what the line on the slave device does, step by step, and how the master recompiles the two bytes into one variable?

Also wondering if there is there a better/faster way to do this. Eventually there will be several slaves sending information to the master, all of the information will be either an unsigned int or unsigned long.

The purpose of this being that the slave device takes readings and does some processing, sends the constantly changing result to the master for displaying on an lcd screen.

Apologies if this is long and rambling. I found a few topics searching about this but didn't understand them very well. Trying to understand more about bitwise operators now but an example of how it works in this code would be really helpful.

Peter_n

The Slaves are not sending data whenever they feel like it, they are responding to the Wire.requestFrom() from the Master. So the Master controls the I2C bus.

The Wire.write() can send a number of bytes. The second parameter is the number of bytes. If the second parameter is omitted, only one byte is send, but just one byte is boring...

I prefer a struct to create a package and transfer that. Both the Master and the Slave must know the struct of course.

This is with a buffer:
Code: [Select]

byte buffer[10];
buffer[0] = 0x25;
buffer[1] = 0x75;
Wire.write( buffer, 10);



In the Master, the Wire.requestFrom() requests data from the Slave, and waits for it, puts the data into a buffer and returns the number of bytes received.
So you don't need the Wire.available() at all, the Wire.requestFrom() already returns the number of data bytes in the buffer.
Code: [Select]

byte buf[10];
int n = Wire.requestFrom( 2, 10);
for( int i = 0; i<n; i++)
{
  buf[i] = Wire.read();
}


Or use the readBytes()
Code: [Select]

byte buf[10];
int n = Wire.requestFrom( 2, 10);
Wire.readBytes( buf, n);
if ( n != 10)
  Serial.println("Error, didn't receive 10 bytes");


If the Master only need the first 4 bytes, it can do Wire.requestFrom ( 2 , 4 ) ;
It is okay that the Slave still does a Wire.write ( buffer, 10 ) ;
It is part of the protocol that it works, and the Arduino libraries allow it too.

The sizeof() is for the compiler. The compiler fills in the number of bytes of that element. An integer is 2 bytes.

How is my explanation so far ?

nickgammon

Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

jboyton

If I may, I'd like to ask a slightly tangential question.

What is the "etiquette" or protocol for setting the I2C clock speed? Is it determined by the slowest device on the bus? Or would it work if it is increased for communicating with one device temporarily and then restored afterward, without affecting slower devices?

nickgammon

All connected devices have to listen to the bus to see if they are being addressed, therefore the clock speed would need to suit the slowest connected device.

Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

jboyton

That's what I thought.

I have some library code from a well known producer of Arduino hardware and it saves the TWBR, speeds up the clock, transfers the data and then restores TWBR. I was puzzling over how slower devices might respond to that. Maybe not so well?

Peter_n

jboyton, there is a new function: Wire.setClock() in Arduino IDE 1.5.8. I can be used after Wire.begin().
I'm testing now with 200000 (double the speed).

You can do the Multi Speed I2C scan : http://forum.arduino.cc/index.php?topic=197360.0

Code at github : https://github.com/RobTillaart/Arduino/tree/master/sketches/MultiSpeedI2CScanner

As you can read here : http://forum.arduino.cc/index.php?topic=197360.msg1991808#msg1991808 my sketch crashed when the speed was too high.

nickgammon

That's what I thought.

I have some library code from a well known producer of Arduino hardware and it saves the TWBR, speeds up the clock, transfers the data and then restores TWBR. I was puzzling over how slower devices might respond to that. Maybe not so well?
Maybe they are capable of receiving at a faster speed but not sending.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

jboyton

Maybe they are capable of receiving at a faster speed but not sending.
This particular device cannot send; the data flow is only from master (microprocessor) to the device.

jboyton

...my sketch crashed when the speed was too high.
When I overclock this device (sole slave on the I2C bus) it works fine to a certain some point. When I overclock further it doesn't behave properly. And overclocking it further still causes the sketch to "crash". I suspect this is due to the I2C bus hanging.

Is there a line in a document describing the I2C bus where it says that the slowest device determines the clock speed? I know there's something called "clock stretching" which may complicate the issue somewhat.

nickgammon

Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

jboyton

The master provides the clock speed.
"However, there are situations where an I2C slave is not able to co-operate with the clock speed given by the master and needs to slow down a little. This is done by a mechanism referred to as clock stretching."

http://www.i2c-bus.org/clock-stretching/


and

"To be on the safe side it is - in case of doubt - a much better idea to keep the maximum bit rate below the maximum rating at any time rather than exceeding it occasionally."

http://www.i2c-bus.org/speed/



I think that answers the question. Sorry to have bothered you when a few more minutes of searching on the internet would have been sufficient.

Aryl

The Wire.write() can send a number of bytes. The second parameter is the number of bytes. If the second parameter is omitted, only one byte is send, but just one byte is boring...

Code: [Select]

byte buf[10];
int n = Wire.requestFrom( 2, 10);
for( int i = 0; i<n; i++)
{
  buf[i] = Wire.read();
}


If the Master only need the first 4 bytes, it can do Wire.requestFrom ( 2 , 4 ) ;
It is okay that the Slave still does a Wire.write ( buffer, 10 ) ;
It is part of the protocol that it works, and the Arduino libraries allow it too.

The sizeof() is for the compiler. The compiler fills in the number of bytes of that element. An integer is 2 bytes.

How is my explanation so far ?
Ah, so my attempt of requesting two bytes from the slave failed because I never told wire.write() (The slave) to send two bytes, so it was only sending one.


Code: [Select]
Wire.write((byte *)&x, sizeof(unsigned int));

So what's going on here is that wire.write is sending a byte array made from x, and it sends the sizeof an unsigned int, which is two bytes.

Is all that correct?


http://www.gammon.com.au/i2c
Now that explained a bit more, thanks!

The reference should really be edited to mention the information in your "Buffer Length" section, I found that interesting and useful for understanding what actually happens.

So i2c prepares the data to be send by storing it in a buffer (Array), sends it, then the master stores it into its own buffer (Array). And the maximum size of this temporary buffer is 4 bytes, so i2c can only send 4 bytes at a time (A maximum of 4 bytes per wire.write).

Correct?

jboyton

So i2c prepares the data to be send by storing it in a buffer (Array), sends it, then the master stores it into its own buffer (Array). And the maximum size of this temporary buffer is 4 bytes, so i2c can only send 4 bytes at a time (A maximum of 4 bytes per wire.write).

Correct?
I don't think there's any limit in the I2C protocol (I could be wrong). The Arduino Wire library has a BUFFER_LENGTH of 32 for both TX and RX. If you call write(buffer, 33) it will return an error.

nickgammon

So i2c prepares the data to be send by storing it in a buffer (Array), sends it, then the master stores it into its own buffer (Array). And the maximum size of this temporary buffer is 4 bytes, so i2c can only send 4 bytes at a time (A maximum of 4 bytes per wire.write).

Correct?
I believe my page mentioned 32 bytes, not four.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

Go Up