12C master - slave with I2C LCD permanently on slave

I am embarking on a home automation project.

The first phase is controlling my central heating system, by-passing the thermostat with an Arduino Uno. I have a one-wire DS18B20 as the temp sensor and a 16X2 LCD in the kitchen displaying central heating setpoint and actual temperature. The LCD is driven using I2C.

I then have a second Arduino that is acting as a supervisor / data aggregator and drawing data from the central heating Arduino over I2C. This supervisor Arduino then communicates through an Ethernet shield to my Iphone using Arduino Manager.

I have the bare bone of my home automation project intact. It works for a few minutes, then the LCD gradually displays random characters.

I have reviewed several of the I2C ‘multi-master’ solutions and code and read and used most of Nick Gammon’s I2C info (thanks Nick!)

I realize that I have 2 masters, which I2C supports. I want to keep the central heating Arduino as the permanent master for the central heating and keep it writing to the LCD as this is a local self-contained ’level 1’ control system. This must run regardless and have it’s own display (as will the garden irrigation system, and other internet-of-things devices over time). The supervisor / aggregator is just that, I just want it to poll for data from the central heating Arduino and handle the broadcast of information over Ethernet to smart phones, tablets etc.

I realise this is causing turmoil on the I2C bus. The central heating Arduino is acting as permanent master to its dedicated LCD in the kitchen, but then along comes the supervisory Arduino interrupting the party and asking for data. The two Arduinos need to arbitrate between themselves but this is causing the central heating Arduino to simultaneously act as master and slave and upsetting the comms to the LCD. The garden irrigation system is going to do the same.

I cannot determine if the libraries have addressed this. I do not have the software skills to code the solution, but I’m sure I am not the first to want to do this in software. I believe I need to introduce a “bus busy, please try later” routine within an adapted arbitration sequence.

I can speak it and flowchart it, I cannot code it!

I accept that I could drive the LCD as a parallel device, I do have the pins available. However this home automation project is going to expand so I really would like an I2C solution is one is possible.

Thank you in anticipation, Peter.

I realize that I have 2 masters, which I2C supports.

It does but it is not supported by the standard wire library. You need what is called a multi-master library.

It works for a few minutes, then the LCD gradually displays random characters.

So are there pull ups on the I2C bus and have you got plenty of supply decoupling?


Thanks for the fast response. Yes I have used several multi-master libraries and these work well, but they do not seem to allow for a permanently connected LCD being driven by one of the slaves. I would expect this aspect needs to be specifically configured somewhere in the slave's code so that it is not bothered by the requests from the master.

Yes done the usual with pull-ups. I have several I2C buses operating around the house. I've duplicated the system on my workbench with identical results, used different pull-up values and had my scope on the lines. I am confident it is not hardware as I realise, as it stands, the software cannot be expected to cope.


these work well, but they do not seem to allow for a permanently connected LCD being driven by one of the slaves

That does not make any sense. Please post a schematic of what you think will not work along with the code you are trying to run.


Thanks for coming back to me so quickly.

The issue I am experiencing does make sense. Further probing has uncovered this post from Feb 18 2012 by WAYNEFT.

I will try and contact Wayne. I expect that as many folks must have come across it in the last 3 years a solution exists in an updated WIRE library somewhere, or indeed it is in my library and I am not making use of it.

Thanks again for your offer of help, Peter


Posted by WayneFT .......

Actually the Wire library handles the arbitration issue fairly well...a little too well and that's where the problem comes in. As you stated, the master should wait for a stop condition before attempting to gain control of the bus which Wire will do. The real problem comes into play because the Wire library does not support the use of a repeated start between write/read transactions. A typical scenario when reading data from a slave device, using the Wire library, is to initiate a write cycle to the slave address (set the address pointer), send a stop bit, send a start bit and finally read back the data beginning from the address pointer. In a single master system, and for most I2C devices, this setup works just fine.

When you add a second master to the bus, again using the Wire library, the second master will watch the bus and will wait for the stop condition before initiating it's transaction. Unfortunately the first stop condition takes place between the write and read cycles on the first master's transaction. So what ends up happening is the first master ends up with the second master's requested data and the second master ends up with the incorrect data. Here's the sequence of what happens:

Master1 sets address pointer: Master1 sends stop bit: Master2 sees stop bit (bus free): Master2 sets address pointer (Master1 is now waiting for bus to free up): Master2 sends stop bit: Master1 sees bus free and reads back data (data is read from Master2's address pointer): Master1 finishes reading data and sends stop bit: Master2 sees the bus is free and reads the data from the slave device. If the slave device supports autoincrement reads, the data read back from slave for Master2 will start at the address location following the last read from Master1.

The only way to fix this problem is to use a repeated start between write/read cycles which the current version of the Wire library does not support (the developers are working on a patch for this issue). A repeated start takes the place of the stop then start bits so the bus never frees up between write/read cycles so each master can finish it's transaction completely.