I2C freeze on master

On my first big Arduino-project I made a game using the following Arduino's and the I2C-protocol:

1x Mega as master
4x Mega as slave
2x Uno as slave
The Arduino's controll a physical game where the players have to push 96 different buttons, according to how certain lights are controlled by relays. The two uno's are used for a MP3-shield and a timer.

My code might not be perfect at all, but I'm happy with how it works. The only problem is that sometimes my master freezes. This is on different moments, but always when the master processes multiple I2C-communications. Sometimes it completes the whole game without problem, but other times it freezes at different moments.

I used a 1ms delay at the end of the loop on all arduino's, because it looked like this might make the connection most stable. The I2C-cables are up to about 1m long, I can't make them shorter. I added 5K1-resesistors from the 5v-line of the master-Mega on the SDA and SCL line. Alle buttons and relays in the game are connected to seperate power sources and don't use the internal pullups.

The code is quite long, so I uploaded the code of the master and the code of 1 mega slave to Github: GitHub - mrcbrgrs/Arduino-mega-buttons-game. Some comments might be in Dutch, sorry for that.

Who has an idea how I can stop the Mega from freezing?

void receiveEvent(int bytes) {
  master = Wire.read();    // read one character from the I2C
  Serial.println("Bericht van master ontvangen:");
  Serial.println(master);
}


void requestEvent() {

  if (writing == 1){
  Wire.write(slave); // respond with message
  Serial.println("Bericht aan master verstuurd:");
  Serial.println(slave);
  slave = 0;
  writing = 0;
   }
     }

The above codes belong to your slave1 sketch of the GitHub.

receiveEvent() and sendEvent() are interrupt contexts; print() methods are not to be executed here. Set flags in these routines and then use these flags in the loop() to print whatever you want.

Also, in your Master codes, you have requested to read 3 bytes; but, you have taken out only 1 byte. You should empty the buffer by reading all 3 bytes.

How long are the wires, and what kind of wires or cable are they ? Do you use pullup resistors ? Which value ?

I think I prefer a single Arduino board for this project. Perhaps with extra hardware to read all the buttons. 96 buttons is a matrix of 8*12, that requires 20 pins. That is no problem for a single Arduino Mega 2560.

There are situations that a Arduino as a Slave on the I2C bus can be useful. For example when there are already I2C sensors connected and a sensor does not have I2C or needs a special sketch or needs to filter the data, then a Arduino as a Slave can be added to the I2C bus. Your use of the Arduino as a Slave is only to read many buttons ?

GolamMostafa:

void receiveEvent(int bytes) {

master = Wire.read();    // read one character from the I2C
  Serial.println("Bericht van master ontvangen:");
  Serial.println(master);
}

void requestEvent() {

if (writing == 1){
  Wire.write(slave); // respond with message
  Serial.println("Bericht aan master verstuurd:");
  Serial.println(slave);
  slave = 0;
  writing = 0;
  }
    }




The above codes belong to your slave1 sketch of the GitHub.

receiveEvent() and sendEvent() are interrupt contexts; print() methods are not to be executed here. Set flags in these routines and then use these flags in the loop() to print whatever you want.

Also, in your Master codes, you have requested to read 3 bytes; but, you have taken out only 1 byte. You should empty the buffer by reading all 3 bytes.

Thanks, will work to correct those mistakes. :slight_smile:

Koepel:
How long are the wires, and what kind of wires or cable are they ? Do you use pullup resistors ? Which value ?

I think I prefer a single Arduino board for this project. Perhaps with extra hardware to read all the buttons. 96 buttons is a matrix of 8*12, that requires 20 pins. That is no problem for a single Arduino Mega 2560.

There are situations that a Arduino as a Slave on the I2C bus can be useful. For example when there are already I2C sensors connected and a sensor does not have I2C or needs a special sketch or needs to filter the data, then a Arduino as a Slave can be added to the I2C bus. Your use of the Arduino as a Slave is only to read many buttons ?

The wires will be in total about 4 meters. I used seperate 0,5mm2 electric cables (H05V-K) for each line. I added 5K1-resesistors from the 5v-line of the master-Mega on the SDA and SCL line. Already received advice to lower the resistors, but problem is about the same even without resistors.

The use of the slaves is indeed only to control the different parts (buttons, relays, timer and mp3-shield). Didn't think about the grid, that might have been a better option. Will look about getting this to work well, otherwise might replace it (but it'll be a lot of work). Still had some problems with combining the MP3-shield and timer on one arduino, so not sure if they can use the same Arduino or might need some short 30cm I2C-cables, to control them.

The wires will be in total about 4 meters. I used seperate 0,5mm2 electric cables (H05V-K) for each line. I added 5K1-resesistors from the 5v-line of the master-Mega on the SDA and SCL line. Already received advice to lower the resistors, but problem is about the same even without resistors.

The Mega2560 has internal 10k pull-ups for the I2C lines, mind that in the calculation if you think you need lower values to ensure you don't get to big currents.

4 meter probably won't ever work reliable if you even get it to work once. I2C is designed to be a onboard connection between a CPU (master) and some sensors. A bus length of more than 50cm usually don't work if you don't decrease the bus speed substantially. There are driver chips (called I2C bus extenders) that let you increase the bus size but you have to have these drivers on both ends of the long cable.

pylon:
The Mega2560 has internal 10k pull-ups for the I2C lines, mind that in the calculation if you think you need lower values to ensure you don't get to big currents.

4 meter probably won't ever work reliable if you even get it to work once. I2C is designed to be a onboard connection between a CPU (master) and some sensors. A bus length of more than 50cm usually don't work if you don't decrease the bus speed substantially. There are driver chips (called I2C bus extenders) that let you increase the bus size but you have to have these drivers on both ends of the long cable.

Thanks, I'll order some PCA9615 as I2C bus extenders to test out.

mrcbrgs:
Thanks, will work to correct those mistakes. :slight_smile:

The wires will be in total about 4 meters. I used seperate 0,5mm2 electric cables (H05V-K) for each line. I added 5K1-resesistors from the 5v-line of the master-Mega on the SDA and SCL line. Already received advice to lower the resistors, but problem is about the same even without resistors.

I scanned the bulk of the thread looking to see if you have tried the configuration but on a shorter bus. Long bus lengths are problematic. Looking at the pulse shapes with an analyzer (if one's available) often will reveal that due to resistance/capacitance of the bus, adding length itself makes it increasingly difficult for devices at the opposite ends of the bus to "modulate" the voltage levels on the bus. For example, thinking of the extreme case, a bus that has a high resistance might make it impossible for a device at the far end to effectively draw down (pull-down) the voltage as seen at the opposite end. Make sense? An analyzer or even a scope would help. Slower bus speeds are an improving measure as well, IMHO.

This may be of some help. If it were me and I'd confirmed that the I2C bus had clean data/clock traffic, I'd give this some consideration:

Good luck with it. Please let us know what you discover.

GOV