3

Here's a question for anyone knowledgeable of the ways of I2C.

I'm curious about sending multiple writes to a device and was looking at the code for a MPU9250 module.

There is a nice library that compiled straight off the shelf by Kris Winer here.

In one of his code examples he makes multiple calls to a function called writeByte():

// Wire.h read and write protocols
void writeByte(uint8_t address, uint8_t subAddress, uint8_t data)
{
    Wire.beginTransmission(address);  // Initialize the Tx buffer
    Wire.write(subAddress);           // Put slave register address in Tx buffer
    Wire.write(data);                 // Put data in Tx buffer
    Wire.endTransmission();           // Send the Tx buffer
}

here is a (truncated) example of the code calling writeByte():

void initMPU9250()
{  
  writeByte(MPU9250_ADDRESS, PWR_MGMT_1, 0x00); 
  delay(100); 

  writeByte(MPU9250_ADDRESS, PWR_MGMT_1, 0x01);  
  delay(200); 
  writeByte(MPU9250_ADDRESS, CONFIG, 0x03);  
  writeByte(MPU9250_ADDRESS, SMPLRT_DIV, 0x04); 
  .
  .
  .
  etc
}

My question is why call Wire.endtransmission() each time your sending I2C to the same device? I can see one reason straight off the bat which is you may need to call delay after your write() - but in cases where you do not need to call delay, wouldnt it be faster to do something like:

Wire.beginTransmission(address); 
Wire.write(data1);
Wire.write(data2);
Wire.write(data3);
Wire.write(data4);
Wire.endTransmission();

at least when it's possible?

  • Nothing happens with Wire until you do call endTransmission(). If you don't call it then nothing will happen - bytes will just get buffered until the buffer overflows. – Majenko Mar 29 '17 at 14:22
  • that makes sense, but how much over head is associated with the endtransmission between bytes versus running them all in and then calling endtransmission? In my case I'll send a block of six bytes total. – Owen White Mar 29 '17 at 14:28
  • 100% of the work is in endTransmission. There is no "overhead", it's where the transmission takes place. If what you are sending to can cope with you sending lots of bytes together then you could batch them up and do an endTransmission afterwards, but it's not the endTransmission that you are then optimizing, it's the sending of the address (beginTransmission) that you are optimizing. But it all depends on if the device you are sending to understands what you are doing in that case - most I suspect will not. – Majenko Mar 29 '17 at 14:30
  • Its a reasonable question, but no (as others will explain). – Code Gorilla Mar 29 '17 at 15:11
4

No, Wire.endTransmission() doesn't "slow things down". It is, however, critical to the operation of the Wire library.

When you do a Wire transaction all the data you send is first buffered in an internal array. Only when you call Wire.endTransmission() does that data actually get sent out. The actual Wire.endTransmission() doesn't add anything extra to the transmission though.

In your example you are sending a total of 5 bytes (address + 4 data bytes) plus start/ACK/stop bits. In general most devices require you to send specific numbers of bytes in a specific order - the most common being a register address followed by the content of that register. That means 3 bytes. Any more bytes after that in the same transaction will either be ignored or would overwrite the first bytes.

Some devices though would allow <address><value><address><value> to be sent, thus removing the need for the repeated I2C address byte for the device each time. Many won't though.

Other devices (most notably flash memory or SRAM chips) would allow you to do page mode accesses, which would be <address><data1><data2>...<dataN> where the address would automatically increment for each data byte. Again, some may, some won't.

It is entirely down to the device you are sending data to as to whether you are able to batch together multiple blocks of data, and the form that batching has to be in if it is supported at all. So you should look in the datasheet for the device to see just what it can support.

  • Might need to mention the internal buffer in Wiring. The size of that buffer will limit the interaction. – Mikael Patel Mar 29 '17 at 15:14
  • Thank you Majenko - the other device in question is a atmega328p running the wire library. I'll try to work out how well it deals with serial Wire.write()s. Thanks. – Owen White Mar 29 '17 at 16:06
  • @OwenWhite Then it is up to you how you create the protocol. If you program it to cope with multiple batched writes then it can cope with multiple batched writes. – Majenko Mar 29 '17 at 16:16
  • I have just dug out the source to Wire to find the maximum buffer size: 32 bytes. That doesn't include the I2C device address, which is stored separately. – Majenko Mar 29 '17 at 17:05
  • Thanks very much for your help. Actually I use the i2c_t3 which looks like the tx buffer length 258. Thanks very much for your comments. – Owen White Mar 29 '17 at 17:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.