Arduino and I2C LCD freezing.

Hello everyone !

I have used LiquidCrystal library a lot, and always with good results when lcd is near the arduino. But today, i'm trying to make a deported screen. (for an alarm project). Between my LCD and arduino, i have near 3m of rubbon cable. I think i'm dangerously near the 400pF limit of capacitance bus. No power transit in this cable. Just 4pin for LCD (I2C, GND and VCC) and 7 pin for a matricial keyboard) I have 2 pull up resistor at the end of cable, just before the LCD, maybe should-it placed on master side ?

Sometimes, and after hazardous time (sometimes a couple of minutes, sometimes after lot of hours) all my Arduino is freezing. I need to reset it manually, or turn it off. I already have this bug with classical I2C library in a different project. I have resolve it by reducing data on the bus.

I really think I2C is the cause of theses freezing. But with LiquidCrystal, i can't set speed of I2C, and i can't use a timeout function to avoid hanging like I2C.h library permit (instead of Wire.h)

When i disconnect my LCD, all is perfectly working week after week.

I really need your help. Maybe there is a special library or sometimes like that could help me to set I2C ? regards,

@Diesel52,

Try to use pull-up resistors at both ends (of double the resistance value).

Try to have one GND wire between the SCL and SDA line, and one GND at the other side of each.

Lowering the bitrate also helps.

Jean-Marc

TP-cable ?? data and clock to one line in differet pairs (other line to Gnd) one pair - both gnd one pair - Ucc

ZinggJM:
@Diesel52,

Try to use pull-up resistors at both ends (of double the resistance value).

Try to have one GND wire between the SCL and SDA line, and one GND at the other side of each.

Lowering the bitrate also helps.

Jean-Marc

Thx A LOT for answer.

I will put pull-up resistor as you say.

That’s not a twisted pair cable, 16 wire into this cable, and just one GND.
3 meters of this cable : RVV – câble de signal de commande, fil de cuivre noir 26awg 0.12 mm2 RVV 2/3/4/5/6/7/8/10/12/14/16/20 | AliExpress

I have read again my arduino code and see lot of lcd.print inside loop. So i have call-it only if there is needed or states changements.
Actually, when my alarm is working, i dont send I2C information. Should work lot of years like that lol.
But at the scope i can see I2C wave like information are sended. Maybe LiquidCrystal still working by I2C when we dont send anything ?

With 4.7K pull-up resistor at slave side, the wave looks like the attachments picture.

So,
I have reduce bitrates but I2C bus still working.

My arduino is self made on PCB. an Atmega328P and Quartz, 22pf, 1M resistor…
Powered by 15VDC, regulated by 3x 7805 with 0.22R in serial to equilibrate current.
Lot of 100nF Capacitor, few 330uf and three 1000uf because my Atmega must work when power is commutate to the battery.

My cable is connected with 15P DSUB connector,
Around 40mm between my connector and Atmega.

I really dont think that is a hardware problem (excepted my 3m cable, but it must be able to work with this lengh. it will be shorter when installed on wall inside my house)

HI guys.

After lowered the bitrate, uploaded with last version of Arduino IDE, put 4.7K pull-up at the end of my cable.

Has perfectly working this night. But after wakeup, and a couple of minutes after pushing a touch of my keyboard (to activate backlight) all was freezed again !

So, what i do now : - Put 10K pull-up resistor at both end of my cable - Replace my hardware backlight (on/off) by software (two wire inside my cable was used to set on or off backlight with a transistor. I have see that lcd.noBacklight do that by I2C.......... maybe this state switching make some noise ?

And i have do what said into this topic : https://community.particle.io/t/i2c-lcd-display-getting-corrupted-solved/9767/79

I have add " delayMicroseconds(10) " in my library. This topic was about crazy LCD and not freezing, but sometimes when my arduino is not freezing, it was going crazy.

Let see again what could be happen now.

What do you think ?

Hello :)

A new night without freezing but just before dinning my Atmega was freezing again yesterday I have replace 10 Micro seconds delay by 30.

I have also read this post tonight : https://github.com/arduino/Arduino/issues/1476

It explain the only thing who could do that issue : I2C library (commissioned by LiquidCrystal_I2C library) is falling in an infinite while loop because slave is not responding.

I think the best way is to understand why slave is not responding (PCF8574AT bug from my LCD, or maybe my cable capacitance distorts too much my signal ...) But an other solution is to add a timeout inside theses two while function( inside I2C library) that doesnt fix my hardware problem, but could help to stabilize my soft. It's an alarm, it should always work and dont fail. My LCD can became crazy, but it need be able to switch on siren and send SMS if an intrusion is taking place.

I ran into a lockup condition in the Wire library several years ago. The Wire code is simply not robust enough. There are cases as you have seen where the code can lockup in an infinite loop. The condition that I saw was a misbehaving slave with a single master. The slave didn't support reads and assumed everything was a write, including when a read was done. The ack/nak bit is handled differently for reads vs writes. If a slave treats a read as write it confuses the Wire s/w state machine into thinking that there is another master on the bus and the low level Wire code drops into an infinite loop waiting for the other master to finish, but of course that "other master" never does finish as there is no other bus activity since there is no other master. and since there is no timeout in the loop in the Wire, the Wire library hangs forever. There is no fix for this type of situation that can be done in the application code as this a s/w an issue in the Wire library that is triggered by a h/w issue.

It is possible that something similar is happening in your situation. It could be that the slew rate of the signal is right at the edge and every now and then it is isn't fast enough so that the slave "sees" the request as a write instead of a read. If that happens, then the slave will respond incorrectly and will trigger the Wire library lockup condition.

You could try to reduce the overall pullup value to push the current right up to the limit. Just keep in mind that there are usually pullups on the i2c backpack that you need to account for. There is also an interesting h/w solution mentioned here that might be useful: https://hackaday.com/2017/02/08/taking-the-leap-off-board-an-introduction-to-i2c-over-long-wires/

About the "LiquidCrystal_I2C" libraries. Not sure which one you have as there are many of them out there. Regardless of which one you have, there should be no i2c bus activity if the sketch is not calling Wire or LiquidCrytal_I2C API functions.

Not that I think it will matter in this situation, but you could try my hd44780 library to see if it helps. It properly honors some of the LCD timing that some of the other libraries are violating. When there are issues there, it corrupts the LCD vs locks up the processor. Also, hd44780 allows configuring the timing for LCD instructions. This would allow you do increase the amount of time between LCD commands or LCD data writes. It doesn't control the time between i2C writes, just the LCD instructions, so it may or may help in this case.

The hd44780 library is available in the IDE library manager. You will use the hd44780_I2Cexp i/o class. There is tons of documentation included with the library that you can bring up by going to the Documentation example sketch. The first thing to run once you install the hd44780 library is the included I2CexpDiag sketch to make sure everything is working. I highly advice not skipping this step. You may also want to run the included LCDiSpeed and LCDlibTest sketches as they really push the bus during their tests. You could use it to test for reliability of your connections.

You can also read about the library on its github page: https://github.com/duinoWitchery/hd44780

--- bill

Hi bperrybap, thx for your complet post.

The Wire code is simply not robust enough.

Of course, and i know that it mas made for inboard circuits communication and not wired systems, but I2C library, it's one of easier bus to used with arduino. And lot of sensor or other device are available on internet.

There is no fix for this type of situation

I've read somewhere that the while loop in twi.c could be fixed by an added timeout :

One of the original while loop in twi.c :

while(TWI_READY != twi_state){
    continue;
 }

And what i have try today :

static volatile uint8_t timeout2; 

while(TWI_READY != twi_state){
    timeout2++;
    continue;
    if(timeout2 > 1000){
       timeout2 = 0;
       return 0;
    }

I don't know if that will solved my problem, but my system is working longer than yesterday. I have also edit delayMicroseconds from 10 to 40 in LiquidCrystal_I2C Library.

All i do since are making it more stable.

You could try to reduce the overall pullup value to push the current right up to the limit.

You mean reduce my global pullup resistor value ? With ZinggJM suggestion i had see that too low pullup value could reduce too much my signal and the slave doesn't understand at least the wire.begin information.

Regardless of which one you have, there should be no i2c bus activity if the sketch is not calling Wire

So i really need to take a look a new time into my first code, because with Oscope i see activity on SDA line.

I will try your idea about hd44780 library. That could help me.

Also, i know that standard speed of I2C is around 100Khz and that can be up to 3.4 Ghz. Do you think reduce it at 10Khz could help slave (there it is a PCF8574AT) and master (Atmega328P)

And if i don't make I2C working as i need, i will replace it by other system. I have take a look about ShiftRegister. I already have a 74HC165 and 74HC595 on my alarm board, why not add one behin the screen and drive them with three wire ? I just need to find a free pin on my atmega, that will be hard lol.

Again, thank you.

Diesel52:

The Wire code is simply not robust enough.

Of course, and i know that it mas made for inboard circuits communication and not wired systems, but I2C library, it's one of easier bus to used with arduino. And lot of sensor or other device are available on internet.

What I was trying to say was that Wire low level code could and should be better at handling things that may arise from signal noise and/or a misbehaving slave. i.e. the code should never lock up.

There is no fix for this type of situation

You have misquoted me. I said:

There is no fix for this type of situation that can be done in the application code as this a s/w an issue in the Wire library that is triggered by a h/w issue.

There is a VERY big difference between the two. What I was saying is you can't fix this in the sketch or a library that uses the Wire library. To resolve a Wire library lockup, requires code fixes in the low level Wire library code.

I've read somewhere that the while loop in twi.c could be fixed by an added timeout :

One of the original while loop in twi.c :

while(TWI_READY != twi_state){
    continue;
 }

And what i have try today :

static volatile uint8_t timeout2; 

while(TWI_READY != twi_state){    timeout2++;    continue;    if(timeout2 > 1000){       timeout2 = 0;       return 0;    }





I don't know if that will solved my problem, but my system is working longer than yesterday.

I haven't looked at the low level Wire code in a long time. As I recall, if that loop is the one that caused the lockups I was seeing, to fix it required not only timing out but also setting a state variable in the code to reset the state machine so that future transfers would work correctly.

I have also edit delayMicroseconds from 10 to 40 in LiquidCrystal_I2C Library.

Changes to the LiquidCrystal_I2C code (or any other library that uses Wire) are unlikely to matter since this is a low level wire library issue. The issue might be due to a slow slew rate due to the long wires. A few things that might help mitigate against that would be a slower SCK rate and perhaps a small delay between I2C byte transfers. Adding a delay in the LiquidCrystal_I2C library is only adding a delay between LCD instructions (bytes transferred to the LCD) and there are multiple I2C bytes that are transferred for each byte transferred across I2C for each LCD byte instruction. And those multiple i2c bytes for each LCD byte will still be transferred across the i2c bus at the full rate.

An additional cap on the 5v signal on the backpack might also help.

You could try to reduce the overall pullup value to push the current right up to the limit.

You mean reduce my global pullup resistor value ? With ZinggJM suggestion i had see that too low pullup value could reduce too much my signal and the slave doesn't understand at least the wire.begin information.

What I meant by that is to reduce the overall or "net" pullup value to the minimum value allowed by the spec. The overall pullup value can be reduced until the maximum sink current on the signal is 3ma, at 5v the minimum overall pullup value would be around 1.6k That doesn't mean you slap on a 1.6k resistor. It means that the net resistance from all the resistors in parallel on the signal cannot be lower than 1.6k and to get the shortest rise times you would want to make it as small as possible without going over the 3ma current sink limit. You will have to do some math to figure out what values to put each end to get to your target resistance. Just remember to take into consideration that on most i2c LCD backpacks there are 4.7k pullup resistors on the backpack. If you end up using other i2c slaves you would also have to see if they have pullups and account for them as well.

What about adding the line driver/receiver hardware that was shown in the hackaday link I provided? That could fully solve the issue.

So i really need to take a look a new time into my first code, because with Oscope i see activity on SDA line.

I will try your idea about hd44780 library. That could help me.

Also, i know that standard speed of I2C is around 100Khz and that can be up to 3.4 Ghz. Do you think reduce it at 10Khz could help slave (there it is a PCF8574AT) and master (Atmega328P)

Slowing it down might help. You may also have voltage droop issues particularly when/as the backlight is turned on. You may have to add some additional decoupling to help hold it up. The PCF8574/74A/AT are only rated to 100Khz. I have seen them appear to run ok at 400Khz, but that is above their rating.

And if i don't make I2C working as i need, i will replace it by other system. I have take a look about ShiftRegister. I already have a 74HC165 and 74HC595 on my alarm board, why not add one behin the screen and drive them with three wire ?

595's are even more sensitive to noise than I2C. They can easily glitch on the clock signal. You have to be careful with them even when everything is on a breadboard.

--- bill

also setting a state variable in the code to reset the state machine so that future transfers would work correctly.

I don’t do that, only add a timeout :smiling_imp:
And i dont know if syntax is correct in my modifications. My C is a little be rust.

What about adding the line driver/receiver hardware that was shown in the hackaday link I provided?
That could fully solve the issue.

I think your idea around P82B96 is probably a real good point, i will studying it and try to add it in my board.
Up the signal to 12V in cable and reduce it at the end to 5v for the LCD is probably the best point to reduce rising time.
And, i will try to switch my cable by twisted and armed cable. That also could help a lot.

As you can see in my attachments, my signal is really dirty…

What I meant by that is to reduce the overall or “net” pullup value to the minimum value allowed by the spec.

Ok, so if 1.6k should be result for my global pullup (to be around 3mA) i’m actually at 2.4K.
4.7K on board of lcd chip, 10K at the end of my cable and 10k just at my atmega pins.
(My I2C screen is the only one slave in my system, i’m using I2C to print information on this screen)

The PCF8574/74A/AT are only rated to 100Khz.

you’ve been faster than me with datasheet, so, that’s not a good way.

You have to be careful with them even when everything is on a breadboard.

I noticed that last night :stuck_out_tongue:

Thx bill. Everything is working, just this I2C situation that i need to fix and you really help me.

So,

Firstly, my LCD is always working since i had edit twi.c library and modify Microdelay from 10 to 40 inside LiquidCrystal_I2C library.
Encouraging !

Secondly, i have studying driver/receiver hardware you’ve suggested.
There :

suggested PCA9615 and P82B96 devices.
PCA device seems work better but need too much wires for me.
I will try with P82B96, just required one more wire for me, the “high voltage”

I need to make my own shield to be connected behind the 20x4 LCD. This shield must do the same things that this one :

but it need to convert 12V High level SDA/SCL to 5V.

With P82B96 datasheet, PCF8574AT datasheet and one of theses board in my hands, i just drawing this schematic (in attachements) and board.

I dont really understand why there is two capacitor between P82B96 and PCF8574AT device in datasheet, there is around 200pF. I just add them but without understanding. (C2 capacitors in figure 14)

Datasheet values purpose a hundred meter cable, i think it could work with my poor 5m cable…