i2c conflicts

Hello

I am trying to make a machine data collection unit that transmits WIFI data to a network
Using ESP8266-01 & Nano.

I have managed to get this working but i have a problem on the I2c line, ESP can only be used in Master, so every 10 seconds it requests data from the Nano, this works fine, the problem i have is the Nano transmits on the same i2c line to an LCD, this works perfectly until the ESP and Nano connect to the i2c line at the same time.

I have been through loads of blogs and it seems possible to run 2 masters on the same line, the bit of information dont seem to be able to find is anything that shows me how to detect if the BUS is busy, i know SDA & SCL are pulled low when its being used but i cannot find anything on how to tell the other master how to detect a LOW and wait?

I have set up 2 Nano's with an LCD one with a delay offset so i know the crash will happen

Master A:

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <LCD.h>
LiquidCrystal_I2C  lcd(0x3F,2,1,0,4,5,6,7);

void setup() {
  Serial.begin(115200);
  Wire.begin(0x10);
  lcd.begin (20,4); // or for 16 x 2 LCD module
  lcd.setBacklightPin(3,POSITIVE);
  lcd.setBacklight(HIGH);
  lcd.home (); // set cursor to 0,0
}
 
void loop() {
  delay(100);
  Wire.beginTransmission(0x3F);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Master 1");
}

Master B:

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <LCD.h>
LiquidCrystal_I2C  lcd(0x3F,2,1,0,4,5,6,7);

void setup() {
  Serial.begin(115200);
  Wire.begin(0x11);
  lcd.begin (20,4); // or for 16 x 2 LCD module
  lcd.setBacklightPin(3,POSITIVE);
  lcd.setBacklight(HIGH);
  lcd.home (); // set cursor to 0,0
}
 
void loop() {
 delay(99);
 Wire.beginTransmission(0x3F);
 lcd.clear();
 lcd.setCursor(0,1);
 lcd.print("Master 2");
}

Any help or pointers appreciated
Thanks
Simon

Just noticed the Wire.endTransmission() was missing off the above post, i was just testing the results of removing it and it did not seem to have any effect, this is now back in place
Simon

Check the result of each I2C call, if available. A collision will result in an error code or zero byte count, so that you know when to try again. This may not work with the I2C LCD library, unless it is collision aware.

DrDiettrich:
Check the result of each I2C call, if available. A collision will result in an error code or zero byte count, so that you know when to try again. This may not work with the I2C LCD library, unless it is collision aware.

Hi
I had a look at Wire.endTransmission as this determined the result but every time i got a zero telling me it was successful

endTransmission()

Function:
Calls the twi routine that does the actual TWI transmission when in master transmitter mode: It attempts to become the twi bus master and write a series of bytes to a device on the bus. The bytes should have been previously loaded into the Wire library send buffer by the send() call.

The results are returned as a byte. The results are as follows:

0: Successful send.
1: Send buffer too large for the twi buffer. This should not happen, as the TWI buffer length set in twi.h is equivalent to the send buffer length set in Wire.h.
2: Address was sent and a NACK received. This is an issue, and the master should send a STOP condition.
3: Data was sent and a NACK received. This means the slave has no more to send. The master can send a STOP condition, or a repeated START.
4: Another twi error took place (eg, the master lost bus arbitration).

I wonder how you determine that a bus collision really occurred, and whether a transmission was aborted without the expected result. If each master clears the screen, you'll see only the text sent by the last transmission.

DrDiettrich:
I wonder how you determine that a bus collision really occurred, and whether a transmission was aborted without the expected result. If each master clears the screen, you'll see only the text sent by the last transmission.

The problem i get is just garble corruption on the LCD after both masters clash on the i2c

Had a look at the link below and suggest that it waits until the line has been released so is it possible all this is happening without any way to see it and then it crashes in the LCD, if i let it run it sometimes recovers and sometimes goes to a blank LCD and sometimes just keeps running garbled stuff!

Got my original code from this post

but i had to add the LCD library as i couldnt write directly to the LCD as is suggested in the sketch

I suspect a problem in/with the LCD library. If multiple transmissions are required for one command, the results of a collision are unpredictable.

BTW what are the many parameters in the lcd constructor?

DrDiettrich:
I suspect a problem in/with the LCD library. If multiple transmissions are required for one command, the results of a collision are unpredictable.

BTW what are the many parameters in the lcd constructor?

Technically, there are two issues:

  • MultiMaster collisions,
  • Multiple i2c bus acquisitions to send the data bytes to control the LCD.

The 2nd can be avoided in the LCD library, the first can not.
The first is an issue of the i2c s/w & h/w.
Some implementations support multiple masters and some don't.
Whether it works or not or has issues can be either a h/w or s/w limitation.

In terms of the constructor parameters, the code appears to be using fm's "LiquidCrystal_I2C" library vs the one in the IDE library manager. The one in the library manager is hard coded for a particular pin mapping, whereas, fm's library lets you configure the pin mapping between the PCF8574 and the HD44780 pins.

Both fm's library and the library manager LiquidCrystal_I2C libraries do multiple i2c bus transactions to control the LCD. It takes multiple bytes over i2c to send a single nibble to the LCD. And those libraries do those transfers for the nibble in a single I2C bus acquisition. However, they let go of the bus between each nibble. This means that sending the full byte is now interruptible.

While I think using multiple masters to control the same LCD is going to have issues and is likely never going to work correctly/realiably, it is possible to reduce the possibility of the LCD nibble sync being lost by being interrupted by another master during the middle of a byte transfer to the LCD.

If you want, you could try using my hd44780 library package.
It includes support for PCF8574 based backpacks. It will auto locate the i2c address and automatically determine the pin mappings. It also does the all the i2c data transfers to send a byte to the LCD during a single i2c bus transfer. This also offers a performance increase.
It works on all the Arduino platforms including the ESP devices.
It also returns status so you can tell if there were issues on any lcd api functions.
This can get messy as the Print class is used for all the print() functions and the return values from Print pretty much suck as they indicate how many characters were processed. This can make it impossible to know if they were all printed as the app may not know the expected number of characters that should have printed (think about printing a variable that is a number).

hd44780 is available in the IDE library manager.
You can read more about it here: GitHub - duinoWitchery/hd44780: Extensible hd44780 LCD library
The i/o class for PCF8574 based backpacks is hd44780_I2Cexp
When first using it, I'd recommend running the included diagnostic sketch I2CexpDiag to test that everything is working. It will test the i2c signals and do a memory test of the RAM inside the LCD.

--- bill

Bill

Many thanks for that excellent bit of information, gives me a few things to look at!

I may have led you off track, the 2 Nano's talking to the same LCD were replicating my original problem, as my original problem is that the ESP requests from the Nano at a given interval, the Nano is sending information to the LCD as information changes ie machine cycle count updates the LCD for the operator to see, the conflict is when the ESP requests from the Nano and the Nano is updating the LCD at the same time, always works for a few cycles then crashes when conflict occurs.

If the conflict is in the i2c line then i would expect it to be detectable but as i am getting a zero returned i assume its post i2c in the LCD? there is nothing to tell me that the LCD has actually gone wrong thus not allowing me to correct it, lcd.reset() doesnt bring it back after a crash either?

Simon

If the I2C LCD works as described, I'd not bother with it any more in a multi-master environment. At least it would take less time to implement an I2C display from scratch, based on an Arduino, with a safer protocol and better multi-master behaviour.

simon5030:
If the conflict is in the i2c line then i would expect it to be detectable but as i am getting a zero returned i assume its post i2c in the LCD? there is nothing to tell me that the LCD has actually gone wrong thus not allowing me to correct it, lcd.reset() doesnt bring it back after a crash either?

lcd.reset() ? I've never seen that function in fm's library.

i2c bus arbitration is handled at the very low h/w level.
It is based on looking at the signals and detecting if someone else is driving the bus signals.

Collisions or signal corruption, is a potential i2c issue, that if handled would be handled by the i2c h/w or library
but I thought if all the masters supported multi master, then you wouldn't get actual collision signal issues since the masters would do proper multi-master bus arbitration and the looser will jump off the bus with no impact to the winners data transfer.

Just because you are seeing issues with your test enviroment, not mean that they are same issues.
You test environment is not a good test since it is not representing the real environment.
The real environment does not have multiple masters trying to talk to an LCD which creates another set of issues.
The real environment is also using i2c masters from two different implementations, so if for example there are issues in the ESP implementation, the test environment will not see it.

Also, remember that with fm's and the IDE LiquidCrystal library, even if all the masters do fully support multi master and everything is working correctly such that you are not getting actual bus signal corruption, there is the possibility (it will happen) that you will lose nibble sync with the LCD using your current test environment which will cause all future data sent to the LCD be interpreted as garbage.
My hd44780 library will not have that particular issue.

I think the AVR code supports multi master, so I'd be curious if you see the same issue using the hd44780 library code using your current test environment.

Alternatively, if you have pins and can use the extra wires, you could just avoid the issue, and use separate i2c busses for the ESP to AVR communication and the AVR to LCD communication.

--- bill

DrDiettrich:
If the I2C LCD works as described, I'd not bother with it any more in a multi-master environment. At least it would take less time to implement an I2C display from scratch, based on an Arduino, with a safer protocol and better multi-master behaviour.

Huh?
Writing a hd44780 pcf8574 backpack library from scratch is not a trivial thing to do.
I've done it several times.

There isn't much you can to do make things safer for multiple masters talking to the same LCD.
There are MANY issues with respect to allowing multiple masters talk to the same pcf8574 based backpack hd44780 lcd.

There is no way to ensure atomic operations that extend beyond a single byte transfer to the LCD.
It is simply not possible.

So while it is possible to ensure that a data byte transfer to the LCD which involves sending two nibbles and each nibble requires sending 2 data bytes over i2c there is no way to ensure entire operations like LCD initialization are atomic.

My suspicion is that the ESP8266 code doesn't support multi master.
I believe that the ESP h/w includes h/w i2c support that does support it; however, I believe that the current Wire library for the ESP core is using a s/w i2c.

I'd go off and dig through the documentation to figure out if the ESP i2c implementation supports multi master before I do much else.
Also might be worth reviewing the AVR stuff as well as I think there have been multi master issues in the past.

--- bill

Big thanks to all who have contributed,

Based on the feedback it seems like i may be looking for a needle in a hastack and the best option would be to review the project options, it may be possible to add another Nano to specifically deal with the LCD and use RX/TX to pass information between them, was thinking about using ESP-12 but it would just slow everything down while running the transmit code (multi threading would be useful!)
Another thought would be to get the ESP to request the LCD information from the Nano and then push to the LCD, this way i would only have 1 master? but this would have to halt LCD updates while the ESP transmits to the network and depending on the connection status this can take up to 5 sec

Lots to think about but thanks again for your contributions!

Simon

simon5030:
Based on the feedback it seems like i may be looking for a needle in a hastack

I don't think this is a needle in a haystack at all.
Multi-master mode and its behavior is fully specified in the i2c spec.
Either the implementation supports it or doesn't.
The first thing I'd do is to go read about the ESP and AVR libraries and see if they claim to to support multi-master.
If they claim to support it, then read the i2c spec to understand how multi-master arbitration works and see if it works the way you need it work. (I believe it will not corrupt an in progress data transfer)

Using multiple masters trying to talk to a single LCD is a bad test environment as it is not testing your original environment and is also going to introduce other issues, particularly given the i2c/lcd library you are using.

If you are going to try to test this yourself, you are going to need a logic analyzer so you can look at the bus signals to see what the implementations are doing to see if they are conforming to the i2c spec or are misbehaving.

--- bill

Bill

Thanks for the info, i agree with what you have said but it may be that this is beyond my abilities (hence MY needle in a haystack), i will look at the ESP and its capabilities and see what i can find

Thanks
Simon

Just found my homework for tonight!

http://kendziorra.nl/arduino/98-esp8266-i-c-with-arduino-multi-masters?showall=1

Looks interesting

Simon

Looks like ESP does not support multi master

Thaks again for all your help

Simon

My final soliution is to use an LCD with SPI, this takes it off the I2c bus!
Sorted

If you have the extra pins for SPI, then you could have used s/w i2c to add another i2c bus.
SoftwareWire has i2c master support and works quite well on the AVR.
It is a bit tricky to use with other libraries because many libraries hard code the i2c object name as "Wire", but it can be done with the the hd44780 library with the clever use of some macros to trick it to use some other name.

--- bill