Surenoo RGB I2C LCD - unstable i2c communication [solved]

Long story short: I have bought this Surenoo RGB I2C LCD and it works unreliable. It seems that after a period of time (10 minutes) the I2C bus hangs and the code freezes.

the short question is: does someone know this Sureeno display and has a working library to share with me?

Long: I have some experience with i2c LCDs, but this LCD drives me crazy.

The display has an AIP31068L (close to the HD44780, but timing parameters differ for shure), the RGB LEDs are driven by a PCA9633

The i2c scanner sees both adresses the display @ 0x3E , the RGB IC @ 0x60 (and the 0x03 - works as designed).

As far as I understand the datasheet, the display should be used in 8bit mode.

I have tested the - DF Robot Libray - Grove Library - The HD44780 from Perry with the constructor hd44780_I2Clcd lcd(i2c_addr)

I get these unstability with all 3 libraries. So I suspect the display is somehow more different than expected.

The i2cdiag reports the pullup resistors are existing if the display is connected. The behaviour doesn't change if I add two extra 10K resistors.

Therefore I modified the low lewel i2c send of DFF Robot to see, what' happening on the I2C Bus. learnings: - only the LCD i2c communication produces errors. - Error codes from Wire.endTransmission() are 2 and 3. If I get an error 4 - the sketch stops. - the errors occures during text mode (starting with 0x40) and command mode (starting with 0x80), - i never see communication errors when talking to the RGB chip

Datasheet of Display http://surenoo.tech/download/01_SLC/1602/SLC1602LO.pdf?spm=a2g0s.imconversation.0.0.751b3e5fbkQ0Q9&file=SLC1602LO.pdf Suggested Library from vendor https://wiki.dfrobot.com/Gravity__I2C_16x2_Arduino_LCD_with_RGB_Font_Display_SKU__DFR0554?spm=a2g0s.imconversation.0.0.751b3e5fbkQ0Q9

It's not so much about the wasted money (10USD), but basically the display is quite that what i would like to use - and integrated i2c LCD with RGB backlight.

My target is an UNO clone, the used dupont wires are around 10cm.

Are there any suggestions I can do to find out, what's wrong with my display?

Sorry for the long post - please don't kill me with your answers - I'm not a native speaker...

this is some serial debug information with additional comments,

15:43:44.557 -> +++++++++++++++++++++++++++++
15:43:44.557 -> 
15:43:44.557 -> red
15:43:44.557 -> r
15:43:44.604 -> L2  40 20    --> first occurance of Error 2 while writing a char
15:43:48.337 -> green
15:43:48.337 -> g
15:43:48.337 -> L2  40 67
15:43:48.337 -> L2  40 62
15:43:52.110 -> blue
15:43:52.110 -> b
15:43:52.110 -> L2  40 75
15:43:55.915 -> reg
15:43:55.915 -> r
15:43:55.915 -> L3  40 38   --> first occurance of Error 3 while writen a char
15:43:59.667 -> cmd
15:44:00.067 -> 
15:44:00.067 -> L2  80 C0   --> sequence of lot of lcd.setCursor - some fail
15:44:00.307 -> L2  80 C0
15:44:00.547 -> L3  80 80   
15:44:00.747 -> L3  80 80
15:44:00.947 -> L2  80 C0
15:44:01.027 -> L3  80 80
15:44:01.587 -> L3  80 80
15:44:02.350 -> L2  80 80
15:44:02.550 -> red
15:44:02.550 -> r
15:44:06.312 -> green
15:44:06.312 -> g
15:44:10.114 -> blue
15:44:10.114 -> b
15:44:13.874 -> reg
15:44:13.874 -> 
15:44:13.874 -> L3  80 C0r
15:44:17.678 -> cmd
15:44:17.838 -> 
15:44:17.838 -> L2  80 C0
15:44:17.918 -> L3  80 80
15:44:18.078 -> L2  80 80
15:44:18.238 -> L4  80 80   --> Error 4 at command 0x80 0x80 and caboom *!*

edit: solved with help of this forum: follow the first 5 pages or https://werner.rothschopf.net/202009_arduino_liquid_crystal_wire_en.htm

This device is different than any of the devices supported by the hd44780 i/o classes. (I have not ever seen a device like this) The real solution is to create a new hd44780 library i/o class for this device.

When you used the hd44780_I2Clcd i/o class what happened? Was it working if you turned on the backlight manually by directly talking to the PCA9633dp2

I2CexpDiag cannot be used to test the device as the hd44780_I2Cexp i/o class is for LCDs that use a PCF8574 or MCP23008 based backpack. It can test the i2c signals but not the actual LCD.

That said, from looking at the AiP31068 datasheet, it looks like the protocol is the same used by the hd44780_I2Clcd i/o class. However.... the hd44780_I2Clcd i/o class does not know how to control the PCA9633dp2 RGB chip. And the data RAM writes for the device seem be slower than the most LCDs . It shouldn't be a problem using a 100Khz clock but if you use a higher clock and want hd44780 to do the proper timing you will need to use setExecTimes(uint32_t chExecTimeUs, uint32_t insExecTimeUs) to extend the instruction time. i.e. use setExecTimes(2000, 45)

If you call setExecTimes() do it before you call begin() Alternatively for some simple testing, you could alter the hd44780.h header file to set the default instruction time by changing HD44780_INSEXECTIME to 45 (2 us longer than the 43us for a data write)

Then you would need to control the RGB chip manually to turn on the backlight.

--- bill

thank you for digging into my problem.

When you used the hd44780_I2Clcd i/o class what happened?

it was the same like with the other two libraries, it starts as it should, it displays the output, sometimes it looses a character but it continues to run, and after a while the sketch freezes.

What I see with my test, all these 2, 3, 4 errors happens ONLY when talking to the AIP31068L. Never had an ACK error when talking to the RGB chip.

I even tried the 1.8.13 today which has an somehow improved Wire.h but it has no effect on my results.

Is there more information what could cause these return codes 2/3, or finally 4 on Wire.endTransmission?

were the 10K pull up to high? is it worth testing with lower values?

edit 15:40 aaah, it's getting well better with a 4K7 resistor network @3V3 ... quite a lot other resistors to test with

noiasca:
I even tried the 1.8.13 today which has an somehow improved Wire.h but it has no effect on my results.

1.8.13 added some code to fix a timeout issue in the AVR Wire library that can cause a lockup in the Wire library code when there are multiple masters or i2c signal instability/noise.
However, it is not enabled by default so the default behavior is to work just like it always did.
You have to call setWireTimeout() to turn it on.

Is there more information what could cause these return codes 2/3, or finally 4 on Wire.endTransmission?

These type errors are usually due to i2c wiring issues or noise on the i2c signals.
Either issues in the wiring itself (poor connections, too long etc…), or improper voltages (too high, too low, or mixing voltages like 5v and 3v devices on the same bus), or issues with the pullups like missing, or resistance value too low

aaah, it’s getting well better with a 4K7 resistor network @3V3
quite a lot other resistors to test with

wait, you are using 3v?
The datasheet for the SLC1602O shows it using 5v.
Please describe in detail what Arduino board you are using and how everything is wired up.
If you are mixing 5v and 3v i2c master / slaves, you need to use proper level shifting.

For picking pullups, it should not be a trial and error process.
The i2c spec defines what the maximum current allowed can be.
The maximum current and the i2c bus voltage can be used to calculate the minimum resistance value.
Typically the resistance does not need to be this low to get a working / stable system unless the wires start to get a bit long.
The biggest thing to ensure is that the overall resistance is not so low that the maximum current is exceeded.
Doing so can cause signalling issues as the devices can no longer pull the signals low or can overheat or potentially even be damaged.

The display was sold as 3.3-5V and the seller confirmed that's 3.3V compatible. The mixture of voltages was from testing only.

Nevertheless, I'm back to 5V only.

My target is an UNO clone

Currently I get the best results with 2K7 Pullups. Optimized my wiring to the shortest duponts I have available, about 6cm to the breadboard with the resistors, about 10cm to the Display. yellow SCL A5 green SDA A4

My next step will be to add the pullups directly to the LCD to get rid of the breadboard

|500x242

20200725_093621m.jpg|800x388

You have a Uno clone with holes for I2C header pins etc. You could solder header strip.

You could solder a pair of pullups to some header strip. Plug in to Uno when required.

Personally, I like these clones that provide extra holes. They let you wire external electronics without resorting to a clunky breadboard.

As a general rule, the I2C bus should have one pair of pullups. Many Ebay modules provide pullups on the pcb. You must be careful with multiple modules. Duplicated pullups will still work but can sink too much current.

David.

david_prentice:
You could solder a pair of pullups to some header strip. Plug in to Uno when required.

good idea. makes the wiring easier. Made two versions.
still, the 2k7 give more stable results than the 4K7…

I would expect 4k7 to be fine for a Uno. I would expect 10k to be fine. Obviously with good Dupont wires to good soldered header pins.

I would expect 2k7 - 4k7 to be fine for an ESP32.

If you really get unreliable operation, there is something wrong with the Surenoo electronics.

David.

david_prentice: If you really get unreliable operation, there is something wrong with the Surenoo electronics.

According to the datasheet this LCD is a bit slower than typical hd44780 displays. It could be that the LCD is stretching out the clock due to the master sending instructions too quickly. This might be triggering one of the issues in the AVR Wire library causing the lockup. Or it could be that the LCD is returning NAK to indicate that instructions are commingin too quickly. If that were the case, I would think Wire would return error codes of 2 or 3

Two things could be tried to see if it might help. I would first run the hd44780 library and use lcd.setExecTimes(4000, 80) This will approximately double the instruction times shown in the datasheet to see if might be related to any sort of instruction overrun issue.

Next I would turn on the AVR Wire library timeout code fixes to see if the Wire library can recover from the issue instead of locking up. Use Wire.setWireTimeout() to use the default timeout. See if you get error code 5 If so there are some other options in setWireTimeout() to try to recover.

--- bill

When I set Wire.setWireTimeout(26);

  • each LCD command (and the rgb chip also) will end with a code 5.
  • no 2/3/4 in 10 minutes (well, possible because of the 5)
  • the sketch doesn't freeze any more (well, that's nice)
  • the LCD still stops working after some time
  • the RGB chip doesn't work at all - RGB stays black

more or less, it's the same behavior for any value >0 to aprox 200 When I set

Wire.setWireTimeout(400); - the code 5 disappers, and I'm back to some 2/3 - the RGB is working again - the lcd works for about 5 minutes - I get a code 4 - and afterwords more or less each command ends in a code 5 - LCD and RGB stop working, - sketch is still running

the only explanation for setWireTimeout I found so far is the comment in the wire.cpp,

  • Sets the TWI timeout. *
  • This limits the maximum time to wait for the TWI hardware. If more time passes, the bus is assumed
  • to have locked up (e.g. due to noise-induced glitches or faulty slaves) and the transaction is aborted.
  • Optionally, the TWI hardware is also reset, which can be required to allow subsequent transactions to
  • succeed in some cases (in particular when noise has made the TWI hardware think there is a second
  • master that has claimed the bus). *
  • When a timeout is triggered, a flag is set that can be queried with getWireTimeoutFlag() and is cleared
  • when clearWireTimeoutFlag() or setWireTimeoutUs() is called. *
  • Note that this timeout can also trigger while waiting for clock stretching or waiting for a second master
  • to complete its transaction. So make sure to adapt the timeout to accomodate for those cases if needed.
  • A typical timeout would be 25ms (which is the maximum clock stretching allowed by the SMBus protocol),
  • but (much) shorter values will usually also work. *
  • In the future, a timeout will be enabled by default, so if you require the timeout to be disabled, it is
  • recommended you disable it by default using setWireTimeoutUs(0), even though that is currently
  • the default. *
  • @param timeout a timeout value in microseconds, if zero then timeout checking is disabled
  • @param reset_with_timeout if true then TWI interface will be automatically reset on timeout
  • if false then TWI interface will not be reset on timeout

if there is more to know about, please point to RTFM ... but where's that manual?

I am intrigued. I would expect I2C transactions to work 100% with AiP31068 chip and also with the PCA9633 chip.

I have ordered the Surenoo module to see for myself. It is just a question of weeks / months for the item to arrive.

David.

Sorry, it wasn't my intention to "promote" that product up to now, and I hope these 10USD wont kill you. Delivery to Austria took about 2 months in the current situation.

I have played around with different other LCDs including i2c backpacks, I've adopted a library successfully for the ST7070 chip, I'm using several other I2C components, but things on that LCD seems to be completely different.

UK takes 8-20 days. But sometimes MUCH longer.

You piqued my interest. I expect I2C devices to work 100% from a bus interface point of view. Of course new silicon chips often come with surprise "features".

But this is nothing new. Just a LCD controller with I2C serial interface. I expect the silicon to be 100%.

David.

well, took the datasheet, started from scratch and came up with a simple test sketch.

// lcd 8bit testsketch 

#include 
const byte lcdAddr = 0x3E;
const byte wait = 39;
const uint16_t waitlong = 1530;

void lowlevel(byte zero, byte one)
{
  Wire.beginTransmission(lcdAddr);
  Wire.write(zero);
  Wire.write(one);
  byte result = Wire.endTransmission();                    // stop transmitting
  Serial.println(result);
}

void initialization()
{
  delay(500);
  lowlevel(0x80, 0x30 | 0x08 | 0x04);  // function set
  delayMicroseconds(wait);
  lowlevel(0x80, 0x08 | 0x04 );        // display on off control
  delayMicroseconds(wait);
  lowlevel(0x80, 0x01);                // display clear
  delayMicroseconds(waitlong);
  lowlevel(0x80, 0x04 | 0x02);         // entry mode set
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println(F("---------------------------"));
  Wire.begin();
  initialization();
  lowlevel(0x40, 'A');
}

void loop() {
  delay(1000);
  lowlevel(0x40, 0x30 + millis() % 10);  // print something
  static byte i;
  i++;
  if (i > 15)
  {
    lowlevel(0x80, 0x01);                // display clear
    delayMicroseconds(waitlong);
    i = 0;
    Serial.print(F("runtime:"));
    Serial.println(millis() / 1000);
  }
}

Went in the park and - it's still running after 50 minutes. Not a single i2c error, the display is still putting out each character.

I am sure that we can devise a test suite that puts the LCD through its paces.

And run continuously for millions of operations without any glitches.

David.

noiasca: When I set Wire.setWireTimeout(26);

  • each LCD command (and the rgb chip also) will end with a code 5.

A timeout of 26 us is VERY short; WAY too short. That timeout is much shorter than the default 25,000 us when setWireTimeout() is called with no parameters. I would expect getting timeouts with a very short delay/wait like that.

It sounds like you didn't do what I had asked in post #8, which were two very specific things to try to determine if this issue was related to overrunning the LCD with instructions.

i.e. if there is an instruction overrun happening, the chip may be doing things to the i2c bus to indicate to the master that it is sending instruction too quickly. it may nak requests (errors codes 2 or 3) or stretch out clock signals which can create issues or even lock up the Wire library due to the Wire code getting confused that there is another master and waiting indefinitely for the other non existent to do a request on the bus.

First thing to do is run the hd44780 library hd44780_I2Clcd i/o class with increased inter instruction timing to see if the issue goes away as that will ensure that the LCD device is never overrun with instructions.

The second was to see what type of errors happen when the hd44780 library is using increased inter instruction timing.

These are useful/needed pieces of information to try to narrow down the issue by eliminating potential LCD instruction overruns.

--- bill

I just ordered one of these. The shipping was as much as the actual LCD. :angry:

I'll look at adding an hd44780 library i/o class for this device. Not sure how I'll handle the RGB setting in the API. But handling backlight control with more than just a simple 0-255 intensity is something I've been considering handling for quite a while now. This will be a good excuse to finally solve it.

--- bill

It looks as if we have both ordered this LCD on the same day.

It will be interesting to see whether Royal Mail beats the US Postal Service. Which packet arrives first !!!

David.

It sounds like you didn't do what I had asked in post #8,

I read all comments very carefully. I prefer to do changes in a short sketch where I can see what's happening. All my testing showed so far, that a simple extension of i2c write delays doesn't have a big effect on the stability.

But ok, I did a test with your library and an example based on hello world:

/ lcd_sureenoo_HD44780
// based on hello world

#include 
#include 
#include  // i2c LCD i/o class header

hd44780_I2Clcd lcd;
//const int i2c_addr = 0x3e;
//hd44780_I2Clcd lcd(i2c_addr); // use device at this address

const int LCD_COLS = 16;
const int LCD_ROWS = 2;
void setup()
{
  Serial.begin(115200);
  Serial.println("lcd_sureenoo_HD44780");
  int status;

  //Wire.setWireTimeout(); // bperrybap #8: Use Wire.setWireTimeout() to use the default timeout.
  
  lcd.setExecTimes(4000, 80);
  status = lcd.begin(LCD_COLS, LCD_ROWS);
  if (status) // non zero status means it was unsuccesful
  {
    hd44780::fatalError(status); // does not return
  }
  lcd.print("Hello, World!");
  lcd.setCursor(0,1); // just for the first line
}

void loop() {
  //delay(1000); // runtime: runtime:480 seconds
  delay(100);  // runtime 37 seconds
  lcd.print(millis() % 10);  // print something
  static byte i;
  i++;
  if (i > 15)
  {
    lcd.clear();
    i = 0;
    Serial.print(F("runtime:"));
    Serial.println(millis() / 1000);
  }
}

depending on the slow down delay in the loop, the display freezes, either very soon or after minutes.

Wire.setWireTimeout();

will lead to a blink code of the LED (is that 4 times?)

further more you suggested:

The second was to see what type of errors happen when the hd44780 library is using increased inter instruction timing.

which modifaction is needed to see the wire error code from your library?

noiasca:
I read all comments very carefully. I prefer to do changes in a short sketch where I can see what’s happening. All my testing showed so far, that a simple extension of i2c write delays doesn’t have a big effect on the stability.

Delays between i2c messages isn’t really the same as ensuring that LCD instructions are not sent to the slave faster than the timing specified in the datasheet.
How exactly did you do the delays?
Keep in mind is that given the way the Wire library lower level code is written no actual i2c transfer happens until endTransmission() is called. Everything is buffered up and sent at the end. So any desired delays have to be done either before beginTransmission() or after endTransmission()

But ok, I did a test with your library and an example based on hello world:

depending on the slow down delay in the loop, the display freezes, either very soon or after minutes.

Wire.setWireTimeout();

will lead to a blink code of the LED (is that 4 times?)

Did the hd44780 library ever display characters on the LCD?
i.e. before setWireTimeout() was done?

In that code, the blinking will be done by fatalError()
If you see blinking it means that the hd44780 begin() failed and the led will blink the begin() return code.
A code of 4 from the library means that it didn’t find a device. For an i2c slave device it means that it didn’t find a LCD slave device on the i2c bus.
If you don’t specify the address, the code will probe the bus looking for a slave at addresses 0x20-0x27 then 0x38-0x3f.

I haven’t really done any testing on Arduino IDE 1.8.13
I’m going to run a few tests to see if the Wire library works with setWireTimeout() being called and hd44780 doing some probing and heavy i2c bus activity - just to see if they broken the Wire code with their Wire library “fixes”.

which modification is needed to see the wire error code from your library?

You can’t get the Wire error code from the hd44780 library.
The Print class interface of write() simply returns the number of characters written. Which will be zero or 1.
For all the other hd44780 library calls, it returns a hd44780 library return code not a Wire code.
This is because the library works on many different h/w platforms and it provides a consistent interface across all of them.

I think this issue is going to take looking at logic analyzer traces of the i2c signals to see what is happening.
Do you have a logic analyzer? i.e. something like a Saleae or a USBee etc…

— bill