LCD I2C initialization problem

Hi guys!
I'm making my own library for LCD (HD44780) with i2c. And I have met problem with initialization. I'm doing everything that datasheet says and there's a problem when I'm setting it to 4 bit mode. Method that sends data to LCD works fine, I double checked it. I'm sending 0x28 to LCD, which means 4 bit mode, 5x8 dots, two lines and then sending byte that turns off cursor and blinking. And now the problem occurs. The LCD should be blank, but it's not. The cursor is blinking on the position of second line in the first character place. I went to see how other people set it to 4 bit mode and I saw that send 0x02 byte which data says return home command and I'm confused because this works fine. So my question is why they are sending return home command and not function set command?

check again Figure 24 4-bit interface in the datasheet.
It's requested that you send a clear

Function set (Set interface to be 4 bits long.)
Interface is 8 bits in length.

Function set (Interface is 4 bits long. Specify the
number of display lines and character font.)
The number of display lines and character font
cannot be changed after this point

Display off

Display clear

Entry mode set

As I can't ask other authors - I ask you: why do you want to send a function set command when the datasheets says to send a Display clear?

1 Like

Big thanks, it worked. But still I don't know why in some libraries sending 0x02 just works fine?

If the HD44780 is already in 4-bit mode, it will quite happily accept lcd_command(0x02)

When you press reset button on an Arduino, it only resets the MCU.
It will not affect the LCD.
Obviously an Arduino running an LCD sketch will send the 4-bit initialisation sequence to the HD44780. A proper LCD library will ensure that this sequence will work whether the LCD is in 8-bit or in 4-bit mode.

Sit down with the HD44780 datasheet and a nice cup of tea.

Oh, you could omit 0x02 if you want. And just clear the screen with setting the cursor position and printing spaces. But 0x02 is easier.

David.

My guess is that if you were having issues with your 4 bit initialization you were not doing the proper 4 instruction sequence to reliably get the LCD into 4 bit mode.
The last 3 instructions in hd44780 datasheet in figure 24 have nothing to do with it.

There is a VERY long comment with a full explanation of how this sequence works in my hd44780 library in hd44780.cpp (in the begin() function), and short version on the hd44780 wikipedia page:

You didn't post the sequence that this refers to nor your code or instruction sequences, but my guess is that you are not properly initializing the LCD into 4 bit mode and are possibly misinterpreting the "0x02" instruction.

I have yet to see an Arduino "LIquidCrystal" type hd44780 library where the comments in the code indicate that the author actually understands the 4 bit initialization sequence.
The comments are totally wrong in the Arduino LiquidCrystal library so it is not a good example to look at for trying to understand what is happening.

There is also a note on page 27 of the hd44780 datasheet about the use of FunctionSet that is incorrect. There is some explanation about this in the hd44780 library hd44780.cpp module. - see the begin() function.


When you say libraries are sending a 0x2 are referring to something like line 133 in the LIquidCrystal library?

    // finally, set to 4-bit interface
    write4bits(0x02);

If so, that isn't sending a 0x02 but rather is sending a 0x20 - the hd44780 instruction width is always 8 bits regardless of the width of the communication width.
And all the sending of a 0x03 bytes above that code are actually sending 0x30 or 0x33 to put the LCD into 8 bit mode (which is not what the comment says) so that the 0x20 instruction can put the LCD into 4 bit mode.

The last 3 instructions in the figure 24

  • display off
  • display clear
  • entry mode set

are not part of the 4 instruction sequence used to reliably get the host and the LCD into 4 bit mode and into nibble sync on the h/w interface.
You can do those additional 3 instructions, or not do them, do them any order you want, or do different instructions since when you get to that point, the host and the LCD are in sync and can communicate so any instruction can be sent/used.
The critical part of the "initialization" is the 4 function set commands that are designed to put the LCD into 8 bit mode which allows the host to put the LCD into 4 bit mode.
It really isn't actually initialization but rather is getting the host and the LCD into synchronization on the h/w interface (both in 4 bit mode and both in nibble sync) by using a sequence of carefully selected instructions that when performed, guarantees that the LCD will be in 4 bit mode and expecting the upper nibble of the next instruction byte when it completes regardless of which mode the LCD was in (4 bit or 8 bit) or which nibble the LCD was expecting when the sequence started.

--- bill

Methinks i will just stick to using the library. :grinning:

You can use the code example below to verify that your 4 bit initialization code is working properly.
Adjust it to work with your lcd code/library.
Run it and then press reset several/many times. The code should always start over no matter how many times you press reset or how rapidly you press reset over and over again.
If you ever see garbled text after pressing reset, then your initialization code is not doing the proper initialization sequence.

The idea behind the code is to print something (anything) very rapidly so to increase the odds of catching the instruction transfer between the two nibbles when the reset button is pressed.

To increase the odds even more, you could add a small delay in your lcd code between were you send the two nibbles.

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

void setup()
{
	lcd.begin(LCD_COLS, LCD_ROWS);
}

int counter;
void loop()
{
	lcd.setCursor(0,0);
	lcd.print("HelloWorld ");
	lcd.print(counter++);
}