Problem Setting up I2C Handshake

Hi everyone

I am trying to get bidirectional communication via I2C set up between two Arduinos:
I want ArduinoA to send a byte to ArduinoB. ArduinoB then turns on the led at pin13 and sens a byte back to ArduinoA. ArduinoA then turns on the led at pin13 as well.

I can send a byte from ArduinoA to ArduinoB. ArduinoB the turns on the LED. However, after that, ArduinoB just sort of stalls. It never sends anything over I2C, it stops sending the serial commands.

I have connected A5 to A5 and A4 to A4 with 3.9k Pull Up resistors added.

Here is my code. Its based on Nick Gammons tutorial (Gammon Forum : Electronics : Microprocessors : I2C - Two-Wire Peripheral Interface - for Arduino)

This is the Master (Arduino Duemillenove):

#include <Wire.h>
const byte MY_ADDRESS = 25;
const byte SLAVE_ADDRESS = 42;
int counter = 0;
byte b;

void setup() 
{
  Wire.begin (MY_ADDRESS);
  Wire.onReceive (receiveEvent);
  Serial.begin(9600); 
  pinMode(13,OUTPUT);
}  // end of setup

void loop() 
{ 
  if (counter == 0){
    //I want this block to be executed once.
    //It could also be in setup, but I will need it within my loop later down the line.
    Serial.print("begin transmission1 ");
    Wire.beginTransmission (SLAVE_ADDRESS);
    Wire.write (1);
    Wire.endTransmission ();
    counter = 1;
  }
}  // end of loop

void receiveEvent (int numBytes)
{
  digitalWrite(13,HIGH); //the led does not turn on
  Serial.print("Receiving Data "); //this is never printed to serial
  while (Wire.available () > 0)
  {
    b = Wire.read ();
    Serial.println(b);
  }  // end of while available
  Serial.print("begin transmission2 "); //this is not printed to serial either
  Wire.beginTransmission (SLAVE_ADDRESS);
  Wire.write (1);
  Wire.endTransmission ();
} // end of receiveEvent

This is the Slave (Arduino Uno):

#include <Wire.h>
const byte MY_ADDRESS = 42;
const byte OTHER_ADDRESS = 25;
byte c;
byte val = 2;
void setup () 
{
  Wire.begin (MY_ADDRESS);
  Wire.onReceive (receiveEvent);
  pinMode(13,OUTPUT);
    Serial.begin(9600); 
}  // end of setup

void loop() 
{
  Serial.println("Serial working"); //this acts as expected, but stops once the LED is turned on
} 

// called by interrupt service routine when incoming data arrives
void receiveEvent (int numBytes)
{
  digitalWrite(13,HIGH); //This works ok.
  Serial.println("LED turned on");  //this never gets sent
  Wire.beginTransmission (OTHER_ADDRESS); 
  Serial.println("transmission started");
  Wire.write (val);
  Wire.endTransmission ();
  Serial.print("transmission ended");
  delay (20);
}

Any suggestions?

The receive event must return before the I2C bus is free, so initiating another transmission inside the receive event is impossible, it might have frozen waiting for the bus to be free

cool. that should fix it.

thanks.

Ok, slightly improved, but this is still not working the way I want to.

Basically, I can do all I described in the original post. ArduinoA sends a byte to ArduinoB. ArduinoB turns on LED, sends a byte back to ArduinoA. ArduinoA turns on LED.

I want to keep them talking, sending bytes back and forth. However, ArduinoA seems to be unable to send a second byte, or ArduinoB cannot receive it.

Heres my code

ArduinoA (master, duemillenove):

// Based on a tutorial by Nick Gammon

#include <Wire.h>
const byte MY_ADDRESS = 25;
const byte SLAVE_ADDRESS = 42;
byte b;
boolean byteReceived = false;

void setup() 
{
  Wire.begin (MY_ADDRESS);
  Wire.onReceive (receiveEvent);
  Serial.begin(9600); 
  pinMode(13,OUTPUT);
  //This seems to work:
  Serial.print("begin transmission0 "); 
  delay(200);
  Wire.beginTransmission (SLAVE_ADDRESS);
  Wire.write (1);
  Wire.endTransmission ();
}  

void loop() 
{ 

  if (byteReceived){
    //this part only executes once, presumably becouse the receiveEvent only executes once
    digitalWrite(13,HIGH);  // the led gets turned on
    Serial.println("byte received ");
    Serial.println("begin transmission1 ");
    Wire.beginTransmission (SLAVE_ADDRESS);
    Wire.write (1);
    Wire.endTransmission ();
    Serial.println("end transimssion1 ");
    byteReceived = false;
  }

}  

//this part also only seems to execute once:
void receiveEvent (int numBytes)
{
  while (Wire.available () > 0)
  {
    b = Wire.read (); //never tested this
  }  
  byteReceived = true;
}

Arduino B (Slave, Uno):

#include <Wire.h>
const byte MY_ADDRESS = 42;
const byte OTHER_ADDRESS = 25;
byte c;
byte val = 2;
boolean byteReceived = false;
void setup () 
{
  Wire.begin (MY_ADDRESS);
  Wire.onReceive (receiveEvent);
  pinMode(13,OUTPUT);
  Serial.begin(9600); 
} 

void loop() 
{
  if(byteReceived){
    //this part only executes once. 
  Serial.println("byte1 received");
  digitalWrite(13,HIGH); 
  delay(50);
  Wire.beginTransmission (OTHER_ADDRESS); 
  Serial.println("transmission started");
  Wire.write (val);
  Wire.endTransmission ();
  Serial.print("transmission ended");
   byteReceived = false;

  }
} 

// called by interrupt service routine when incoming data arrives
 //it only executes once. If I send in more data (by resetting my master arduino) it does not execute again.
void receiveEvent (int numBytes)
{
  byteReceived = true;
}

Arduino B doesn't receive the byte. You have to call Wire.read() in your actually get the bytes read and (that's important) to have the acknowledge sent.

yep. that fixed it.

thanks

edit: posting code, in case anyone is interested:

Master:

// Based on a tutorial by Nick Gammon

#include <Wire.h>
const byte MY_ADDRESS = 25;
const byte SLAVE_ADDRESS = 42;
byte b;
boolean byteReceived = false;

void setup() 
{
  Wire.begin (MY_ADDRESS);
  Wire.onReceive (receiveEvent);
  Serial.begin(9600); 
  pinMode(13,OUTPUT);
  //This seems to work:
  Serial.print("begin transmission0 "); 
  delay(200);
  Wire.beginTransmission (SLAVE_ADDRESS);
  Wire.write (1);
  Wire.endTransmission ();
}  

void loop() 
{ 

  if (byteReceived){
    digitalWrite(13,HIGH);  // the led gets turned on
    Serial.println("byte received ");
    Serial.println("begin transmission1 ");
    Wire.beginTransmission (SLAVE_ADDRESS);
    Wire.write (1);
    Wire.endTransmission ();
    Serial.println("end transimssion1 ");
    byteReceived = false;
    Serial.println("b");
    Serial.println(b);
  }

}  


void receiveEvent (int numBytes)
{
  while (Wire.available () > 0)
  {
    b = Wire.read (); //never tested this
  }  
  byteReceived = true;
}

Slave:

#include <Wire.h>
const byte MY_ADDRESS = 42;
const byte OTHER_ADDRESS = 25;
byte c;
byte val = 3;
boolean byteReceived = false;
void setup () 
{
  Wire.begin (MY_ADDRESS);
  Wire.onReceive (receiveEvent);
  pinMode(13,OUTPUT);
  Serial.begin(9600); 
} 

void loop() 
{
  if(byteReceived){
    //this part only executes once. 
  Serial.println("byte1 received");
  digitalWrite(13,HIGH); 
  delay(50);
  Wire.beginTransmission (OTHER_ADDRESS); 
  Serial.println("transmission started");
  Wire.write (val);
  Wire.endTransmission ();
  Serial.print("transmission ended");
   byteReceived = false;

  }
} 

// called by interrupt service routine when incoming data arrives
void receiveEvent (int numBytes)
{
   while (Wire.available () > 0)
  {
    c = Wire.read (); //never tested this
  } 
  byteReceived = true;
}