Bug on I2C (onReceive)

Well, to make it more clear, i will post two codes that do the same thing, one works and the other doesnt due to this bug.

Working code:

#include <Wire.h>
char buffer[258];
#define LED 13
byte poop=0;
 #define THIS_ADDRESS 0x9
 #define OTHER_ADDRESS 0x8


 void setup() {
   pinMode(LED, OUTPUT);
   digitalWrite(LED, LOW);
   Wire.begin(THIS_ADDRESS);
   Wire.onReceive(receiveEvent);
   Serial.begin(115200);
 }

 void loop() {
   if (poop==1)
   {
     reply();
   }
 }


void reply()
{
  Wire.beginTransmission(OTHER_ADDRESS);
    Wire.write(0xFE);
    Wire.endTransmission();
    poop=0;
}

 void receiveEvent(int howMany){
   int counter=0;
  while(0 < Wire.available())
  {
    buffer[counter]=Wire.read();
    counter++;
  }
  
  switch (buffer[0]) {
    
    case 0xFF: //master is checking if slave is alive
    poop=1;
    break;
  }
 }

In this example, i change a global variable name inside the “receiveEvent()” function. Then, outside of this function, i reply with the code inside “reply()”. This works perfectly.

Now:

#include <Wire.h>
char buffer[258];
#define LED 13
 #define THIS_ADDRESS 0x9
 #define OTHER_ADDRESS 0x8


 void setup() {
   pinMode(LED, OUTPUT);
   digitalWrite(LED, LOW);
   Wire.begin(THIS_ADDRESS);
   Wire.onReceive(receiveEvent);
   Serial.begin(115200);
 }

 void loop() {
 }




 void receiveEvent(int howMany){
   int counter=0;
  while(0 < Wire.available())
  {
    buffer[counter]=Wire.read();
    counter++;
  }
  
  switch (buffer[0]) {
    
    case 0xFF: //master is checking if slave is alive
   [b] Wire.beginTransmission(OTHER_ADDRESS);
    Wire.write(0xFE);
    Wire.endTransmission();[/b]
    break;
  }
 }

If i try to reply directly inside “receiveEvent()”, the I2C bus will crash and he whole MCU will stop working. It wont be able to do the “Wire.endTransmission()”.

This can easily be replicated by using the above indicated code.

Working code for the master is here:

#include <Wire.h>
byte buffer[258];


 #define THIS_ADDRESS 0x8
 #define OTHER_ADDRESS 0x9


 void setup() {
  
   Wire.begin(THIS_ADDRESS);
   Wire.onReceive(receiveEvent);
   Serial.begin(115200);
   Serial.println("Ready!");
   Serial.print("Checking if slave is alive...");
   Wire.beginTransmission(OTHER_ADDRESS);
   Wire.write(0xFF);
   Wire.endTransmission();
 }

 void loop() {
   delay(100);
 }

 void receiveEvent(int howMany){
   int counter=0;
  while(0 < Wire.available())
  {
    buffer[counter]=Wire.read();
    counter++;
  }
  switch (buffer[0]) {
    
    case 0xFE: //master is checking if slave is alive
    Serial.println("Present!");
    break;
  } 
 }

BR

 void receiveEvent(int howMany){
   int counter=0;
  while(0 < Wire.available())
  {
    buffer[counter]=Wire.read();
    counter++;
  }
  
  switch (buffer[0]) {
    
    case 0xFF: //master is checking if slave is alive
  Wire.beginTransmission(OTHER_ADDRESS);
    Wire.write(0xFE);
    Wire.endTransmission();
    break;
  }
 }

You don’t do Wire.beginTransmission or Wire.endTransmission inside a receive event. You just reply (and with a single reply).

Examples here:

http://www.gammon.com.au/i2c

And it isn't a bug, so I moved the thread. It works perfectly if you follow the suggestions in my forum.

Then, outside of this function, i reply with the code inside "reply()". This works perfectly.

Except, again, that isn't the way to do it.

Ok, thanks for the tip Nick! :slight_smile: