Custom Character Creation using hd44780.h library

Hi all,

first of all special thanks to Bill Perry for his hd44780 library.

I am working on a big project using 16x2 LCD displays with I2C backpacks and I was challenged with getting different backpacks. Sometimes they come with a PCF8574T, sometimes with PCF8574AT -> so by default their I2C addresses are either 0x27 or 0x3F.

As I have already produced quite some devices I am running into the issue to keep track with the used backpacks, when I want to update the firmware and I have to deal with 2 different versions. I want to avoid this to keep the update service as simple as possible.

Bill's library helped me to overcome the issue to care about the I2C addressing as it checks this automatically. So far so good.

But now I am confronted with a new challenge -> creating custom characters which I use to display the currently selected operation mode to the user.

In the "old" sketch I used F.Malpartida's LCD library and the creation of custom characters was no problem. I used the "byte" method to create the special characters with the help of an online character tool.

With Bill's library the display either stays blank or shows strange custom characters - depending on how I set the sketch up. Looking at examples I tried several approaches (e.g. converted the bytes to hex values) but could not succeed.

Attached pls find a little sketch, just focussing on the custom character creation and display.
The screen stays blank as soon the lcd.createChar lines are active, so there seems to be the issue.

Can somebody of the audience give me the right kick please.

#include <Wire.h>
#include <hd44780.h>                       // main hd44780 header
#include <hd44780ioClass/hd44780_I2Cexp.h> // i2c expander i/o class header

hd44780_I2Cexp lcd; // declare lcd object: auto locate & config exapander chip

// LCD geometry
const int LCD_COLS = 16;
const int LCD_ROWS = 2;

// custom characters for different modes
// little "1":
uint8_t btn1[8] = {0x02, 0x06, 0x02, 0x02, 0x07, 0x00, 0x00, 0x00};
// little "3":
uint8_t btn3[8] = {0x07, 0x01, 0x07, 0x01, 0x07, 0x00, 0x00, 0x00};


void setup() {
  // SetUp of LCD
  lcd.begin(LCD_COLS, LCD_ROWS);

  // create 2 custom characters
  lcd.createChar(0, btn1);
  lcd.createChar(1, btn3);

  lcd.home();
}

void loop() {

  lcd.setCursor(0, 0);
  lcd.print("Little ONE  ");
  lcd.setCursor(15, 0);
  lcd.write((uint8_t)(0));
  delay(1000);

  lcd.setCursor(0, 0);
  lcd.print("Little THREE ");
  lcd.setCursor(15, 0);
  lcd.write((uint8_t)(1));
  delay(1000);
}

I need some more information about the issue you are having as the code you have provided works for me as expected.
I need to know what version of the hd44780 library you using, what Arduino board you are using, what backpack you you are using (photos?) and I need an example of code that fails to work correctly for me in order to be able to replicate any possible issues.

Also, have you run the diagnostic sketch to test the LCD h/w and verify that the library is properly communicating with the lcd device?

What about the included hd44780_I2Cexp CustomChars example? does that work on your lcd module?
File->Examples->hd44780->ioClass->hd44780_I2Cexp->hd44780Examples->CustomChars

One thing that the hd44780 createChar() code does that no other LCD Library does is properly transitioning between DDRAM mode to CGRAM mode and back.
All the other libraries leave the LCD stuck in CGRAM mode, when createChar() returns, which means that with other libraries, after you do a creatChar(), until you do a setcursor(), clear(), or home(), any write() calls that you do will not go to the display but rather will trash your custom characters.
The hd44780 interface is very dumb as it has no way to restore the LCD back to where it was prior to moving from DDRAM mode to CGRAM mode. However, the hd44780 library handles this in a smart way, if possible, it will read the LCD to get the cursor position so that it can restore it after sending the custom character.
If reads are no possible, it will set the cursor position back to 0,0

The PCF8574 backpacks are capable of reads so the hd44780 library attempts to read the LCD to be able to restore it back to exactly where it was prior to sending the custom character data.
It is possible that your backpack as an i2c issue (perhaps it doesn't have proper pullups on it) and the i2c bus is having in issue and locking up the Wire library.

I'd be curious if the diag sketch reports any issues.

One other thing that may affect you in the near term is wanting to put the custom character data into flash on the AVR processors.
Currently, there is no support for using the AVR proprietary progmem stuff for custom character data.
It will be in the next release of hd44780, which should be available in a few weeks, but it isn't there right now in the latest release which is 0.9.0

--- bill

Thanks Bill for your reply.

Following some facts as requested:

  • the Arduino type is a Nano
  • Arduino IDE: 1.8.3
  • latest hd44780 library (v0.9.0)
  • the backpacks I use, come from different sources, but all of them come from China, whether being bought directly via eBay, Amazon or via local sellers which import them from China and sell them with 300% surplus or more - so: same quality (and so far I have tested and used more than two dozens in different projects without any problems, when using F.Malpartida's New LiquidCrystal library)
  • The critical display was built in a test device with which I test the general functions of my product (a device which works with two stepper motors, a sensor, a rotary encoder and the display)
  • I replaced the suspicious display (LCD incl. backpack) by another one -> this works flawlessly with your lib and custom characters
  • Then tested this suspicious display connected via I2C to the Nano
  • my "old" sketch, using F.M.'s lib -> everything ok incl. my two custom characters
  • my "old" sketch, modified to use your library (i2c expander i/o class header) -> Backlight ON, nothing on the screen, no normal text, no custom characters
  • I ran your diagnostic sketch -> everything works, all tests passed successfully, address was recognized
  • I ran your custom character test sketch -> without any issues, displaying all custom characters
  • the sketch from my first post, which works on your display -> doesn't work on my display, but on ALL other displays, which I have at hand

Unfortunately this is somehow not very logical to me why

  • the dubious display passes the whole test routine
  • your sketches all work with the dubious display, my own little test sketch not,
  • but no issues with pure text display
  • all my other displays work flawlessly with all of your and my own sketches ...

Strange, isn't it?

Raimund

Following the test protocol:

********************************************************************
Serial Initialized
--------------------------------------------------------------------
I2CexpDiag - i2c LCD i/o expander backpack diagnostic tool
--------------------------------------------------------------------
hd44780 lib version: 0.9.0
--------------------------------------------------------------------
Reported Arduino Revision: 1.8.3
CPU ARCH: AVR - F_CPU: 16000000
--------------------------------------------------------------------
 A4: digital pin: 18
 A5: digital pin: 19
SDA: digital pin: 18
SCL: digital pin: 19
--------------------------------------------------------------------
Checking for required external I2C pull-up on SDA - YES
Checking for required external I2C pull-up on SCL - YES
--------------------------------------------------------------------
Scanning i2c bus for devices..
 i2c device found at address 0x27
Total I2C devices found: 1
--------------------------------------------------------------------
Scanning i2c bus for all lcd displays
 LCD at address: 0x27 | config: P01245673H | R/W control: Yes
Total LCD devices found: 1
--------------------------------------------------------------------
LCD Display Memory Test
Display: 0
 Walking 1s data test:	PASSED
 Address line test:	PASSED
--------------------------------------------------------------------
Each working display should have its backlight on
and be displaying its #, address, and config information
If display is blank, but backlight is on, try adjusting contrast pot
If backlight is off, wait for next test
--------------------------------------------------------------------
Blinking backlight test: to verify BL level autodetection
If backlight is mostly off but
you briefly see "BL Off" on display with backlight on,
then the library autodetected incorrect BL level
and the library cannot autoconfigure the device
--------------------------------------------------------------------
Displaying 'uptime' on all displays
--------------------------------------------------------------------

It is very strange.
I have no idea why the backpack and LCD works with the included examples but not with your test sketch.
Without being able to see and probe the actual h/w, I'm stumped as to what is happening.
The main differences between other lcd libaries and hd44780.
hd44780 does all the i2c data transfers for a LCD operation in a single i2c transaction vs multiple.
hd44780 will do reads from the LCD for createChar().

Are you using a bootloader or are you using ISP programming?
The reason I ask is that a bootloader can affect the timing from reset to when sketch code is called.

Can you post some photos of the offending backpack/LCD?
How are you powering the device? From a USB port on a host?

Maybe that LCD is marginal on its timing or is a bit slower than the reference timing.
The hd44780 honors the reference timing in the hd44780 spec but hd44780 is quite a bit faster than fm's library.

Here are a couple of things to try:

  1. print something to the LCD before calling createChar() to see if the LCD is working before createChar() is called.

  2. Insert a 10 millisecond delay before and after lcd.begin()
    See if that changes anything.

2)Add this line above lcd.begin()

  lcd.setExecTimes(5000, 100);

It will slow down the sending of commands and data the the LCD by telling the library that clear/home takes 5ms instead of 2ms and that other commands and data takes 100us instead of 37us.

--- bill

Thanks Bill,

will try your proposed actions on Tuesday or Wednesday as today is already pretty late in Central Europe and I will find some time only after Tuesday to extend the testings.

Will come back then with more details.

Good night
Raimund

Good evening,

eventually got the time to test the device.
Here are the results:

  1. My sketch works with more than 20 displays with similar backpacks (some with 0x27, some with 0x3F as I2C address - due to either PCF 8574T or PCF 8574AT onboard of the backpack(s) using your HD44780 library
  2. There is just one display which only works flawlessly with F.Malpartida's library
  3. Without changing the sketch, using your library, the display just lights up the backlight, but doesn't show any text
  4. Then I added an lcd.print command line just before the creation of the special characters, as you recommended above -> BINGO: the display showed this text line and after that worked with pure text as expected
  5. But: it failed to show the customized little 1" and "little 3" -> it shows garbage instead of the little figures, while the accompanying text in the same line is ok
  6. I added the two delays of 10ms -> no effect (I think, the action in 4. does pretty much the same?) to the customized numbers
  7. I added the recommended line before lcd.begin:
lcd.setExecTimes(5000, 100)

-> no effect to the customized numbers; text is displayed ok.

Wrapping things up:

  • I will mark this display as partially faulty and only use it with either pure text and your library or with F. Malpartida's library.

Raimund

This concerns me particularly that the diags are not detecting any sort of issue. I'll go take a very close look at the differences between what hd44780 does and what fm's code does and try to narrow down what is going on.
The information you have provided has eliminated quite a few things.
I may have a few more things for you to try to try figure what is happening.
I want to make sure that there isn't an issue in the hd44780 code.
--- bill

Yeah, it's a bit weird what is happening. I wouldn't mind having a bad display, but when it behaves differently with two libraries there must be something in the not correctly working lib.

On the other hand: the display (or the backpack) as such seems to be out of tolerance somehow compared to all my other devices. So I will wait for your new instructions to continue testing.

Raimund

@Bill: could you already find some time to investigate a bit deeper into my case?
If not - take your time, as the display is the only one in my 40+ displays which I am currently testing.

Raimund

I was out of town for while. (went to Tennessee to see the Eclipse)

Given that it only occurs on that particular backpack/LCD, my guess is that this is a PCF8574 part issue vs a s/w library or LCD issue.

I'm guessing that something is not working correctly when the PCF part is read.
None of the other i2c backpack libraries do any reads from the part.
hd44780 will do a read so it can restore the LCD back to the exact state it was in prior to creating the character.
No other library does this (not just the backpack libraries). In fact, all the other libraries I've seen leave the LCD in CGRAM mode after sending the character data to the LCD, which means that if you attempt to send a character to the LCD after creating a custom character, it will corrupt the custom character ram.
The work around is to call setCursor(), home(), or clear() after a custom character is created.

One thing that you could try is to tweak the hd44780 code to not try to read the part.
In the file hd44780.cpp in the function createChar()
change this line: (line 643 in the 0.9.0 release)

ddramaddr = status(); // fetch status which includes ddram address

to this:

ddramaddr =-1;

This will disable the read.

I'm guessing that this will likely resolve the issue.

Would it be possible for me to get this board from you?
That way I could see what the real issue is by examining it and probing with logic analyzer.
This will allow me to verify whether or not it is some sort of subtle s/w issue in the hd44780 code that reads the part.

--- bill

Bill,

the eclipse might have blacked out the sun for some minutes, but apparently your brain soaked all the light ...

This will disable the read.

I'm guessing that this will likely resolve the issue.

BINGO: the disabled read in the cpp made the display behave like normal again.

Would it be possible for me to get this board from you?

Sure - I guess you're in the US?

Pls send me a PN with your address and I will send the device across the ocean.
As an engineer I am excited to learn a bit more of what made this little devil behave like this.

Raimund

Sure - I guess you're in the US?

Not exactly. He's in Texas.

Don