I2C LCD display getting corrupted [SOLVED]

@BulldogLowell, with 4.7K pull-ups and 820K pull-downs I get a failure within minutes so that is a no go. I will duplicate what you did to get a second confirmation. :slight_smile:

1 Like

On Spark, wire.write(data) just enqueues the data and then wire.endTransmission() does the real work of sending the data. So I don’t think you need the delay after write() after all, just after endTransmission() should be enough.

I’ll test it, thanks.

1 Like

@bko, as usual I am reminded of why you make such a great Elite :wink: I have been running the dual delay code without problems and I will now test with the single delay as well. :smile:

UDPATE: removing the delay after write caused display corruption almost right away.

1 Like

likewise here…

I’ll continue testing with the delays back in place…

Bulldog,
Just flashed your example code with your libraries on to the spark. I will check back in the morning. I am using 10K resistors for pull up. Would you like me to switch to 4K7’s?

Good point, I have been testing with the 4K7’s …

UPDATE
All night with no corruption

1 Like

@BulldogLowell:
Thank you for your work on that library, but I can´t test it right now since i mentioned that my current Core is in use and my Photon not shipped :slight_smile: so I can test it as soon as I got my new hardware. Anyway, I see that @bko and @peekay123 are involved in that threat; they are far more experienced than me. I think that all is in good hands.

If you want I can update my “tutorial” when this is ready, that other folks not stumble upon same problems?

Good Idea… once we confirm we can point folks to the updated library. I tried uploading to Spark’s web IDE, perhaps that will work OK, once I figure out how to make that work. :wink:

@BulldogLowell, @bko, ran all night an no corruption. So, it is clear that considering slave processing time during I2C (or other protocols for that matter) transaction is critical. @bko is correct in saying that the Core is fast enough that issues commands/data to a slave without considering the time it takes for that slave to “intake” can cause data corruption, as is evident with the LCD display. Since the library does not evaluate the error return from endTransmission(), the delay() are necessary to accommodate the slave processing time. At 120MHz, the Photon will potentially make this a bigger issue.

@bko, do you think adding error checking in the I2C write code of the LCD library is worthwhile?

1 Like

well, if we are waiting for the LCD to process the data, then perhaps the 2microSeconds will work when we get the Photon. We can always revisit the library at that time. Thanks for the assistance and verification.

I pushed the library into the web IDE’s repo, but it doesn’t work properly… I get this issue when compiling the example…

In file included from ../inc/spark_wiring.h:29:0,
from ../inc/application.h:29,
from clockexample.cpp:6:
../../core-common-lib/SPARK_Firmware_Driver/inc/config.h:12:2: warning: #warning "Defaulting to Release Build" [-Wcpp]
#warning "Defaulting to Release Build"
^
clockexample.cpp:7:37: fatal error: LiquidCrystal_I2C_Spark.h: No such file or directory
void setup(void);
^
compilation terminated.
make: *** [clockexample.o] Error 1

any suggestions on what’s wrong?

@BulldogLowell, yup the delay will work. It would be nice to have a mechanism that checks for a NAK from the display but I have to investigate.

Libraries on the IDE are different than using local compile or CLI. In your app (.ino file) you need to refer to library includes with a full path:

#include LiquidCrystal_I2C_Spark/LiquidCrystal_I2C_Spark.h

:smile:

1 Like

Since the return codes from endTransmission are doc’ed, it would nice to use them. As always on small systems, how you deal with and indicate the error can be challenging. I don’t think it is super high priority since the only thing you can really do in this case is retry.

It would also be nice to try adding a delay of 6 after endTransmission instead of the 2+2+2 shown above, since I am having a hard time understanding what the first two delays are really doing–nothing gets sent until endTransmission as I read the code.

@bko, I agree on the error response. One thing to consider is that the LCD may actually hang and will never respond on subsequent retries.

As for the delays, I tried shortening or removing the delays before endTransmission() and found the display corrupted very quickly. The only working version is with the delays, each 2us. :smile:

1 Like

you may have meant:

#include "LiquidCrystal_I2C_Spark/LiquidCrystal_I2C_Spark.h"

:smile:
all done

I actually tried that when I first started adding in the delays (even exactly your 6μS) with mixed luck.

I can experiment with it more in the evenings that come.

2 Likes

As of this morning, using the updated code and Bulldog’s example program, I had no corruption. It was running for 8 hours. Every 8 hour span before had resulted in corruption. Also it is using 10K pull up resistors.

2 Likes

So I’ve run more than a full day on mine…

OK, so let’s call this SOLVED and we can come back to it once we get our new Photons!!!

We’ll leave the delays in the code as is (sorry if we are stealing 2μS from everyone’s life waiting for display updates that my be unnecessary ( @bko ). :wink:

Thanks all for the help everyone!

@peekay123 do you think iit be a good idea for me to post an update in LIBRARIES or do you think this thread is enough?

3 Likes

@BulldogLowell, running over 36hrs without errors so it is solved :stuck_out_tongue: As for posting in LIBRARIES I would say yes if you publish to the IDE. Good job all! :smile:

2 Likes

Thanks @BulldogLowell @peekay123 and @bko !!!

3 Likes

Hi BulldogLowell,
First, Thank you for your work on this library.
Second, I had to further increase the delay times in the library to prevent LCD screen corruptions in a large Core program that I wrote. The library worked fine on shorter lengthed programs, but in my program of about 800 lines, I kept getting corrupted LCD output whenever I was connected to the Cloud. At first, I thought the Wifi signal was disrupting the i2c transmission, but after about ten hours of debugging, trying on three different cores and trying many, many work-arounds/fixes (I’m a programmer with 20+ years experience), I discovered the trick was to increase the delay times in LiquidCrystal_I2C_Spark.cpp Now, it works great. What a relief!
Following is the code as changed. I multiplied the listed delays by 10. I imagine that’s longer than necessary, but I’m not worried about slowing my program down by a millisecond.

Best, Yogi

PS I was using 4.7k pull-ups. I ran noInterrupts before invoking the library calls.


void LiquidCrystal_I2C::expanderWrite(uint8_t _data){
Wire.beginTransmission(_Addr);
delayMicroseconds(20);
Wire.write((int)(_data) | _backlightval);
delayMicroseconds(20);
Wire.endTransmission();
delayMicroseconds(20);
}

void LiquidCrystal_I2C::pulseEnable(uint8_t _data){
expanderWrite(_data | (1<<2)); // En high
delayMicroseconds(10); // enable pulse must be >450ns
expanderWrite(_data & ~(1<<2)); // En low
delayMicroseconds(100); // commands need > 37us to settle
}

1 Like