That's a lot of interesting information Bill - thanks. I'd be happy to work with you to resolve the issue but, as I said on my last post to Tom, the issue only occurs with one particular display which is a fairly new type of OLED 16 x 2 display, so I suspect that the problem resides with that display, however if the OLED has a subtle dislike of your library then perhaps a permanent solution could be devised? I only have the one OLED display, as they are not cheap, so I can't test another to see if the problem is common to them all. If you want to test it yourself I can send it to you, but I would not then be able to do any tests here on your behalf.
Hi,
I meant the soldering technique, using wires or header pins between the two boards?
Thanks.. Tom..
![]()
PS, does the back of all the displays look identical?
please give a link to that particular display and google the respective datasheet.
Just as an example: displays with an AIP31068L might need modified waiting times according to the datasheet.
The purchase URL is: https://www.aliexpress.com/item/32917221249.html
The data sheet is: http://surenoo.tech/download/03_SOL/0301_SOC/SOC1602A.pdf
Yes most standard 5v16x2 displays look similar on the back, there ares some 3v3 displays that have extra circuitry for generating required voltages, but overall largely similar.
Ah, an OLED LCD.
I have seen many issues with these devices depending on which chipset they have used.
Some of issues I've seen:
- The timing is slower than typical hd44780 LCDs
- the chipset used extended the hd44780 instructions and broke FUNCTION-SET
- The CLEAR-DISPLAY instruction does not work the same as a real hd44780
Chips like the IST0010 and the IST0012 are fairly common in OLED LCDs and have most if not all of these issues.
In looking at the data sheet you provided, I can't find which chipset is used.
However, I'm surprised it works at all given the slow timing specified in section 8 command table 8 on page 7
It shows the instruction time for most instructions to be 600us vs the typical hd44780 of 37us
The hd44780 library uses 38us for all but clear and home which are 2ms
The Wire library and I2C overhead will greatly extend the time beyond the 38us but it will not extend it all the way to 600us.
You can set the timing for the hd44780 library using
setExecTimes(uint32_t chExecTimeUs, uint32_t insExecTimeUs)
where chExecTimeUS is the time for clear and home and insExecTimeUs is for all the other instructions.
According to the datasheet this would translate to:
lcd.setExecTimes(2000, 600);
Do that before calling begin()
The biggest issue for chips like the IST chips that they have broken the reliability of hd44780 initialization sequence if trying to use other fonts and they have not implemented CLEAR-DISPLAY properly.
They modified the FUNCTION_SET instruction to extend it by using bit 0 and bit 1 to configure a font.
While those bits were "not used" in the hd44780 function-set instruction, they actually could not be used for something else since they MUST be set to zero to ensure that you can reliably get the LCD back into 8 bit mode when out of nibble sync.
By them using these bits and not holding them to zero they have broken the initialization sequence so it no longer is guaranteed to work if those bits are not zero.
Some other issues in these chipset sets like the IST chips I've seen used in OLED LCDs is that the clear display instruction does not home the cursor.
And in one case the clear instruction didn't write the character to the screen, it filled it with some other character like '@'
I do have some IST0010 and IST0012 devices and have looked at the issue.
It is currently on my list of things see if I can come up with a reliable work around but so far I have not been able to do so.
i.e. warm-start initialization is not 100% reliable
So far, increasing the timing, seems to make things better, but it still has warm-start initialization issues.
I think it might be possible to come with something to work around their issues, but so far I've not been able to come up with something, but then I also haven't spent that much time on it yet.
I suspect that in your case, there is some sort of issue that is causing a loss of nibble sync, i.e. a power glitch, or noise on i2c bus and that calling begin() again doesn't work to get things going properly again because of a reliability issue in the initialization sequence for this chip set.
It definitely could be a timing issue if the chip is really as slow as the datasheet shows.
You can try increasing the instruction timing to see if that helps or removes the issue.But even if the timing change, "fixes" the issue of allowing begin() to re-init the LCD. There will still might be an issue with the clear() function as some chips screw this up.
i.e. for some chips you would need to call home() after clear() to home the cursor.
--- bill
Some of you may have noticed in my previous post I called the device an "OLED LCD" or just LCD, when in fact it is an OLED display not an actual LCD.
Yes terminology and accuracy matters. Oops, my goof.
But the remaining comments about OLED displays that have hd44780 compatible interfaces on them is still relevant to the displays of that type.
--- bill
Have you tried the old fashion 4bit parallel connection?
As @bperrybap has said, it could be timing problems.
Comparable controller.
It already has I2C I/O;
You can choose the I/O config on the board.
Tom..
![]()
The timing problems are with the instruction execution timing not at the electrical signal level.
i.e. the libraries are not using BUSY so they must assume how long the instruction takes to execute.
The typical hd44780 LCD takes 37us for most instructions other than home and clear which take around 2ms.
The datasheet for this OLED says 600us for the non home and clear instructions.
If there is an instruction timing issue, running in 4 bit mode with direct pin control will be much worse than over i2c as i2c adds considerably more overhead to control the pins on the display vs direct pin control.
The time it takes to send the instruction varies depending on processor, library and physical interface.
But even on an AVR UNO using i2c with the hd44780 library the time to send a byte to display will be less than the 600us in the OLED datasheet. (about 550us).
The chipsets are deaf to processing new nibbles or bytes while executing an instruction. So if you send things too quickly to the display, data will be lost.
Depending on the timing and mode a byte or nibble transfer can be lost if sending data while it is still busy executing the previous instruction.
If a single nibble is lost the host and the display are out of sync and garbage will start to show on the display. It will not recover on its own. It requires re-initialization to get the host and display back in nibble sync.
The hd44780 library has the ability to set the instruction timing.
See post #26 for details.
--- bill
Note,
There is one area where the hd44780_I2Cexp io class code violates the hd44780 spec and the spec for this OLED with respect to some electrical signals.
This is the tAS timing.
This is the time from setting data lines and RS to raising E.
tAS on hd4780 is 40ns and on this OLED is 20ns.
The hd44780_I2Cexp code sets the bits/pins in the PCF8574 port register simultaneously when setting the nibble pins and RS as when E is raised.
So the display will "see" all the signals change at the same time vs being set tAS amount of time before E is raised.
While this works on the hd44780, perhaps it occasionally causes an issue on these other chipsets. It depends on how the chip works internally to look at and/or latch the data pins when E is raised.
But even if there was an issue here, it shouldn't cause a loss of nibble sync, it would just send a single garbage byte to the display.
Before jumping to the conclusion that this is the issue, I would want to set the instruction timing in the hd44780 library to see if that clears up the issue since without doing that, the instruction timing for this OLED is being violated by around 50us.
If setting the instruction timing doesn't clear it up then I can provide a way to alter the hd44780_I2Cexp code to properly honor tAS.
It is a one line change to the code.
It isn't being done because it will affect byte transfer times and hence slow down display updates and it wasn't necessary on hd44780 chipsets.
i.e. the time to transfer a byte to the display changes from round 550us to around 750us
--- bill
Thanks for the suggestion Tom, although I see from Bill's latest post that it would not help as it could make timing issues even worse. The manufacturer of the OLED display has many variants and yes there are some with built in I2C interface, but the one I bought just has the parallel interface so I just added an I2C backpack in the usual way and that's when the problems started.
Just tried adding lcd.setExecTimes(2000, 600); before calling begin() but the OLED still crashes (see picture). The crashes only occur post UNO reset, usually about 1 in 5 times. If the OLED initialises correctly I can write to it all day without further crashes.
I'm not sure what you mean by "post UNO reset".
Like is this after a clean powerup/applying power or bashing the reset etc...
Can you fully describe how are you creating this?
i.e. what is hooked up, and what sketch code is running?
A photo of what all is hooked would also be nice so we can see all the wiring and connections involved.
And what if anything you are doing to get it to happen.
--- bill
Post UNO reset = pressing reset button on UNO. Connection is very simple power supplied to UNO via USB, USBASP or USBTinyISP - makes no difference to problem. OLED fitted with PCF8574A backpack connected by Power, Ground, SDA and SCL to UNO in totally standard way. Problem only occurs after pressing reset button about 20% of the time, does not seem to occur when powering up, so could it be an issue that only causes a problem if a powered OLED is reinitialized following reset button pressed? Please see earlier posts for pictures re setup, cables etc.
// Links related to this project:
// Arduino UNO - https://s.click.aliexpress.com/e/_AXDw1h
// Arduino breadboard prototyping shield - https://s.click.aliexpress.com/e/_ApbCwx
// 16x2 displays with IIC - https://s.click.aliexpress.com/e/_9Hl3JV
// 16x2 display with RGB backlight - https://s.click.aliexpress.com/e/_9wgpeb
// Arduino I2C scanner - https://playground.arduino.cc/Main/I2cScanner/
// 16x2 available characters - https://docs.wokwi.com/parts/wokwi-lcd1602#font
// Organising your code with multiple tabs and h files = https://www.youtube.com/watch?v=PWMOb85OGY0
// How to use includes = https://www.arduino.cc/reference/en/language/structure/further-syntax/include/
#include "LCDhelper.h" //local file (not used at present)
#include <Wire.h> // Library file
// Bill Perry's extensible LCD library for HD44780 based LCD displays
#include <hd44780.h> // Library file, main hd44780 header
#include <hd44780ioClass/hd44780_I2Cexp.h> // Library file, i2c expander i/o class header
/*-----( Declare Constants )-----*/
// LCD geometry
const int LCD_COLS = 16;
const int LCD_ROWS = 2;
// Variables
int Count = 0; //A number to display and increment
int status; // holds returned status after lcd.begin if needed
/*-----( Declare objects )-----*/
//hd44780_I2Cexp lcd; // declare lcd object: and specify lcd address as below:
hd44780_I2Cexp lcd(0x27);
// if you don´t know the I2C address of the display, use I2C scanner first (https://playground.arduino.cc/Main/I2cScanner/)
void setup() {
//PowerCycle(); // Power down. delay and power up LCD display to ensure full reset under software control to fix any garbage displayed characters
lcd.setExecTimes(2000, 600);
status = lcd.begin(LCD_COLS, LCD_ROWS);
delay(10);
lcd.backlight(); // Turn on backlight of LCD display screen.
//lcd.noBacklight(); // Turn off backlight of LCD display screen.
lcd.clear(); // Clear display
delay (10);
// Commonly used instruction codes
// lcd.clear(); // Clear LCD display screen
// lcd.home(); // Go to home position (0,0) - column 1 & row 1
// lcd.setCursor(col,row); // Go to position (column, row)
// lcd.print("text"); // Print text start from specified (column, row)
lcd.setCursor(0, 0); // Go to position column 0 & row 0
lcd.print("No crash display"); // Print "Hello, World!"
lcd.setCursor(0, 1); // Go to position column 0 & row 1
lcd.print("Count "); // Print "Count "
lcd.print(Count); // Print the value of the variable Count
}
void loop() {
//PowerCycle(); // Power down. delay, power up & initialise LCD display to ensure full reset under software control to fix any garbage displayed characters
//lcd.setCursor(0, 0); // Go to position column 0 & row 0
//lcd.print("No crash display"); // Print "Hello, World!"
//lcd.setCursor(0, 1); // Go to position column 0 & row 1
//lcd.print("Count "); // Print "Count "
//lcd.print(Count); // Print the value of the variable Count
//Count ++;
delay (1000);
}
void PowerCycle() {
pinMode(2, OUTPUT); // +5v Vcc to power LCD module
digitalWrite(2, LOW); // Power down LCD
delay (100);
digitalWrite(2, HIGH); // Power up LCD
delay(10);
status = lcd.begin(LCD_COLS, LCD_ROWS);
delay(10);
lcd.backlight(); // Turn on backlight of LCD display screen.
//lcd.noBacklight(); // Turn off backlight of LCD display screen.
lcd.clear(); // Clear display
delay (10);
}
Can you read any part number on the i2c chip on the backpack?
It is a package I haven't seen used before on these backpacks.
I'm still trying to understand exactly what is happening.
From what you have said and looking at the code,
You bash the reset and sometimes the display fails to initialize properly.
The PowerCycle() code is not being called.
It also sounds like the power source doesn't matter.
Did I get this correct?
Are you rapidly pressing reset in attempt to interrupt the setup() code?
so as to force an initialization in between nibbles of a byte?
I have seen similar behavior with some OLED displays I was working with.
They were based on IST0010 and IST0012 chips.
It drives me crazy as I have not been able to figure out how to get a reliable initialization and can't figure out why it works vs not works.
Even when initialization is started with host and display in nibble sync.
I gave up on it after a day, but need to get back to it.
I didn't see anything in the datasheet to indicate which chipset it was using.
The capabilities line up with the IST parts.
That said, so many of these datasheets contain errors so even if have one it can have errors in it.
Example, IST0010 indicates a clear time of 6.2ms and all others ZERO.
Clearly the zero is incorrect.
The datasheet you linked to also indicates an error in the CLEAR-DISPLAY instruction. It states:
Does not change DDRAM address
This behavior is incorrect and is the same for the IST parts.
This means that when calling clear() it will not home the cursor like it does on a hd44780 based chip.
One thing that might be useful is to increase the exec times to fully rule that out.
i.e. try using
lcd.setExecTimes(7000, 1600);
which should be more than what is needed.
If that has no effect, make a small change to the hd44780_I2Cexp.h code.
In the function write4bits() around line 1237
Change this:
// Cheat here by raising E at the same time as setting control lines
// This violates the spec but seems to work realiably.
Wire.write(gpioValue |_en); // with E HIGH
Wire.write(gpioValue); // with E LOW
to this:
Wire.write(gpioValue); // with E LOW
Wire.write(gpioValue |_en); // with E HIGH
Wire.write(gpioValue); // with E LOW
This change will ensure that all the signals are fully conformant to the datasheet timing requirements.
note: I never did try this on the displays that I have that were having issues.
And can you print out the value of status so we can see if begin() is failing.
--- bill
There are a few other sketches you could run to really push the i2c bus and the LCD.
- I2CexpDiag sketch
will test i2c signals and do writes and reads of LCD DDRAM - hd44780examples/LCDlibTest
will test various library and LCD functionality but also does some very rapid transfers which is a good stress test of the interface. It will loop with an animation that maintains a timer so you can see how long it has been running.
As shipped, some of the RGB Surenoo displays will fail in just a few seconds running LCDlibTest due to noisy onboard 5v power supplies. Noteable, is the Surenoo SLC1602O.
(yes that is an O (oh) not a zero on the end)
That display is a pretty crappy design and basically doesn't work as shipped if you turn on the backlight.
It can work with additional de-coupling caps soldered on the display PCB.
--- bill
Good point Tom, yes there is serial mode available via the OLED display itself, but it's not functionally (too many wires) and probably not software compatible with the I2C serial bus standard. Maybe someone has developed an Arduino library for this mode, but I've never tried using it. If anyone knows of a library please let us know.
The SIPO chip on the backpack is an AT8574D Datasheet Archive AT8574T datasheet download which presumably is more or less equivalent to a PCF8574.
You bash the reset and sometimes the display fails to initialize properly.
The PowerCycle() code is not being called.
It also sounds like the power source doesn't matter.
Did I get this correct? YES TO ALL - GENTLY PRESS RESET ONCE THEN WAIT FOR INITIALIZATION
Using lcd.setExecTimes(7000, 1600); had no effect.
Changed code starting line 1210 in hd44780_I2Cexp.h but had no noticeable effect
Return value of status is always = 0
Modified code follows:
#include "LCDhelper.h" //local file (not used at present)
#include <Wire.h> // Library file
// Bill Perry's extensible LCD library for HD44780 based LCD displays
#include <hd44780.h> // Library file, main hd44780 header
#include <hd44780ioClass/hd44780_I2Cexp.h> // Library file, i2c expander i/o class header
/*-----( Declare Constants )-----*/
// LCD geometry
const int LCD_COLS = 16;
const int LCD_ROWS = 2;
// Variables
int Count = 0; //A number to display and increment
int status; // holds returned status after lcd.begin if needed
/*-----( Declare objects )-----*/
//hd44780_I2Cexp lcd; // declare lcd object: and specify lcd address as below:
hd44780_I2Cexp lcd(0x27);
// if you don´t know the I2C address of the display, use I2C scanner first (https://playground.arduino.cc/Main/I2cScanner/)
void setup() {
Serial.begin(9600);
//PowerCycle(); // Power down. delay and power up LCD display to ensure full reset under software control to fix any garbage displayed characters
lcd.setExecTimes(7000, 1600);
status = lcd.begin(LCD_COLS, LCD_ROWS);
delay(10);
Serial.print("status is ");
Serial.println(status);
lcd.backlight(); // Turn on backlight of LCD display screen.
//lcd.noBacklight(); // Turn off backlight of LCD display screen.
lcd.clear(); // Clear display
delay (10);
// Commonly used instruction codes
// lcd.clear(); // Clear LCD display screen
// lcd.home(); // Go to home position (0,0) - column 1 & row 1
// lcd.setCursor(col,row); // Go to position (column, row)
// lcd.print("text"); // Print text start from specified (column, row)
lcd.setCursor(0, 0); // Go to position column 0 & row 0
lcd.print("No crash display"); // Print "Hello, World!"
lcd.setCursor(0, 1); // Go to position column 0 & row 1
lcd.print("Count "); // Print "Count "
lcd.print(Count); // Print the value of the variable Count
}
void loop() {
//PowerCycle(); // Power down. delay, power up & initialise LCD display to ensure full reset under software control to fix any garbage displayed characters
//lcd.setCursor(0, 0); // Go to position column 0 & row 0
//lcd.print("No crash display"); // Print "Hello, World!"
//lcd.setCursor(0, 1); // Go to position column 0 & row 1
//lcd.print("Count "); // Print "Count "
//lcd.print(Count); // Print the value of the variable Count
//Count ++;
delay (1000);
}
void PowerCycle() {
pinMode(2, OUTPUT); // +5v Vcc to power LCD module
digitalWrite(2, LOW); // Power down LCD
delay (100);
digitalWrite(2, HIGH); // Power up LCD
delay(10);
status = lcd.begin(LCD_COLS, LCD_ROWS);
delay(10);
lcd.backlight(); // Turn on backlight of LCD display screen.
//lcd.noBacklight(); // Turn off backlight of LCD display screen.
lcd.clear(); // Clear display
delay (10);
}
I just noticed that in the Surenoo SOC1602A datasheet
on the first page there is a clickable link inside the box labeled WS0010
just below the text "Reference Controller Datasheet"
to here:
So this OLED display appears to be using the WS0010 controller.
The WS0010 datasheet matches the IST0010 datasheet.
This controller has different instruction timing, some extensions to the hd44780 instruction set and some incompatibilities.
Also, the WS0010 datasheet (which matches the IST0010) shows a CLEAR-DISPLAY instruction timing of 6.2ms vs 2ms in the SOC1602A datasheet.
and WS0010 & IST0010 show 0us for all instructions vs 600us in the SOC1602A datasheet.
This is the kind of stuff that makes getting a library working reliably difficult.
i.e. no telling what the REAL specs are
--- bill



