Multiple Master/Slave I2C configurations

Hi,

I have a project which uses two Arduino Unos each of which are driving MCP23017 chips. The MCP23017 outputs are connected to LEDs.

The control between the UNOs and MCPs is I2C. As two independent Master/Slave configurations they are both working as expected and the results are good. However I need to make one of the Unos a controlling master such that it can trigger the second master as required.

I am able to control the second master using Master-Master I2C control, but only if I remove the Slave processing from the second configuration. When I try to combine the slave element of the second master the system freezes.

I have noted that it is the SCL bus wire which interconnects the two master/slave configurations that freezes the system - without it connected the two Master/Slave systems work independently ok.

Is it possible to configure two Master/Slaves on the same I2C bus?

I have seen on other topics a simple semaphore control between two Unos and that would work for me, but I thought I2C was more elegant!

Thank you

With two Masters it will go wrong.
The Arduino Wire library for the Uno does take care of the hardware detection for a collision, so you might be able to verify that the I2C bus transaction was okay or not by checking the return value of Wire.endTransmission() and Wire.requestFrom().
However, the Wire library might not detect every situation, and multiple Masters on a I2C bus will go wrong anyway.

You need a single Master that requests data from the Slaves and sends data to the Slaves.

If a Slave is connected to a sensor or extra I/O chip, you might use a software implementation for the Wire library (on any two digital pins) to create an other I2C bus for the sensor.
Sometimes is it easier when the Master also controls the sensors and extra I/O chips.
Does your project really need extra Arduino boards ?

The I2C can not be long, about 50 cm is the maximum.
An Arduino as Slave will be less reliable when interrupts are turned off for some time. That is done in the NeoPixel, OneWire and DHT libraries.

An Arduino as Slave can easily get into trouble. When the Slave is running the onRequest interrupt handler, then it keeps the SCL low. If you have a delay or a Serial function in that interrupt handler, than you will run into trouble even without multiple Masters.

Hi Koepel - thank you for your response.

Ideally the project needs two Arduinos to handle all the peripherals but I guess if I was starting out again I’d review that decision!

Originally I had thought to control both UNOs using input/output connections between the two, but that would require three wires and offer limited functionality compare with two wires of an I2C bus and ‘unlimited’ functionality. However as you say Master - Master looks fraught with issues so I guess it is back to plan A.

What I don’t understand though is the problem arises not with hardware connected but only with software added. I’ll explain!

I set up a UNO as ‘control’ master, connected via I2C to another UNO. Initially this was configured as a Slave. I was able to flash an LED on the second UNO using I2C commands from the control master.

I then added additional code to the second Master to make it behave as a master, but didn’t connect any hardware and the system locked up - I suspect it was due to a conflicting SCL.

To prove this, I removed the ‘flash LED’ code from the second Master (restoring it to a true master/Slave) and it performed as it should. So both bits of code work in isolation but not combined!

I’m sure Babbage didn’t have these conundrums in mind when he designed the first computer!

Koepel:
With two Masters it will go wrong.
The Arduino Wire library for the Uno does take care of the hardware detection for a collision, so you might be able to verify that the I2C bus transaction was okay or not by checking the return value of Wire.endTransmission() and Wire.requestFrom().

If busStatus (the return value) is non-zero in the execution of this instruction:
byte busStatus = Wire.endTransmission();, we understand that the Master could not communicate with the Slave.

If m (the return value) is non-zero in the execution of this instruction:
byte m = Wire.requestFrom(slaveAddress, n);, we understand that the Master has received m bytes data from Slave when the demand was n bytes (m < n). The Master had communication with the Slave for a while and then failed.

If m (the return value) is zero in the execution of this instruction:
byte m = Wire.requestFrom(slaveAddress, n);, we understand that the Master could not communicate with the Slave.