Does an AVR do other things while sending data by I2C?

Sorry for the very basic question, but does the loop() function continue while data is being sent by I2C, because I2C is handled by hardware?

What happens if try to enter a sleep mode like ADC Noise Reduction Mode before the I2C has finished sending? Will the transfer be interrupted? If so, if there a way to tell when the transfer is complete before attempting to enter a sleep mode?

I2C communications are handled by a combination of software with interrupts and hardware. If you put the Arduino to sleep before transmission of a data block is complete, transmission will be suspended.

It might continue when the CPU is awakened, but it would be wise to put in a test or delay to allow the transmission to finish, before activating sleep mode.

The transfer is started in and ends before return of Wire.endTransmission() or Wire.requestFrom().

Depends on the code. All the I2C library code I have seen is blocking, so, no, nothing else happens. That does not mean it has to be like that, I have certainly not seen all I2C library code and there is nothing to stop you writing you own.

Okay, thanks! So the Arduino Wire.h library is blocking and an Arduino in peripheral mode won't do anything else in the loop until a Wire.write transfer is complete?

To the best of my knowledge, yes.

Test by setting a pin high when a data sending starts, and then low at the end. Use an oscilloscope to see how long it takes.

Wire.write() is not blocking.

That surprises me, but thank you, I learnt something.

Are you saying Wire.write() is non-blocking but other Wire functions are? Or they are all non-blocking? That has not been my experience.

Did you read my #3?

Yes, but I don't think I really understood it clearly. My comments are based on my own experience of using Wire on an Arduino. Happy to be corrected, I don't want to mislead @amowry or anyone else.

1 Like

Using this post from Koepel and the associated Wokwi simulation diagram, I modified the code to show the I2C timing as implemented by the Wire library.

// Just a simple test to capture the data for a screendump.

#include <Wire.h>

byte test[] = "Hello World, this is a long string";

void setup() 
{
  Wire.begin();
  delay(100);  // wait 100ms, to make a better screendump
  Wire.beginTransmission(0x27);
  PORTB |= 0b00100000; // Pin 13 goes HIGH at the beginning of the transfer
  Wire.write((char *)test);
  PORTB &= ~0b00100000; // Pin 13 goes LOW at the return from Wire.write()
  Wire.endTransmission();
  PORTB |= 0b00100000;  // Pin 13 goes HIGH at the return from Wire.endTransmission()
}

void loop() {}

Pin 13 is driven HIGH and LOW to show the (simulated) Arduino activity.

Here is what it looks like. Transfer is not even initiated as the Wire.write() function returns.

Now do the same check for Wire.endTransmission() and Wire.requestFrom().

It's actually done, look at the far right of the timing diagram, "13" goes HIGH again

To make sure I understand, are you saying that Wire.write() is blocking because the LED doesn't come on until the transfer is complete?

No, Wire.write() returns even before any transmission is initiated. Putting the Arduino to Sleep just after Wire.write() instruction would "disturb" the transmission.
(I edited post #11 to add the corresponding listing)

But as DrDiettrich said on post #3, transfer ends before return of Wire.endTransmission() : with other words, Wire.endTransmission() only returns when transmission is finished.

=> The right place to put the Arduino to sleep is right after Wire.endTransmission().

1 Like

Thanks, I understand now. How do I use Wire.endTransmission() to tell when the data has been sent?

Nothing more, nothing less than

Wire.endTransmission();

Have a look at the code post #11

1 Like

Great, thanks everyone for all your help!

2 Likes

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.