I purchased an LCD/I2C driver pair and have been trying to get the thing to initialize. I am able to communicate with the I2C driver without issue, but getting the correct initialization sequence has proven to be a real pain.

This is the module and LCD I have: LCD and Driver

The LCD is shown as type 2004A and has J204A etched on the back.

enter image description here

I have read that this particular driver makes use of the LCD 4-bit mode and has the following physical connections to the LCD module (from the link above).

From the schematic, you can derive that:

P0: RS

P1: RW

P2: CS

P3: BL

P4: D4

P5: D5

P6: D6

P7: D7

Considering that data frames are sent (neglecting the ACK, start, and stop) MSB, I would presume that the MSB of the byte shifted into this device is represented at its output as P7 (I could not directly find this in the datasheet, but after a bit of testing it appears true).

Now, with all that aside and after successfully addressing (and receiving an ACK bit) from the I2C driver, one must initialize the LCD module in 4 bit mode and set other parameters - this is where I am completely stuck.

I have written the following init sequence that simply does not work:

void lcdInit(void){

//D7 D6 D5 D4 BL CS RW RS
// x  x  x  x  1  1  0  0 = XC (hex)
    i2c_write(0x2C); _delay_us(4200);
    i2c_write(0x8C); _delay_us(4200); //0x28

    i2c_write(0x2C); _delay_us(120);
    i2c_write(0x8C); _delay_us(120);  //0x28

    i2c_write(0x2C); _delay_us(50);   //0x28
    i2c_write(0x8C); _delay_us(50);   //4 bit mode, N=1(2lines), F=0(5x8)

    i2c_write(0x0C); _delay_us(50);   //0x06
    i2c_write(0x6C); _delay_us(50);   //I/D=1(increment), S=0(display shift off)

    i2c_write(0x0C); _delay_us(50);   //0x0C
    i2c_write(0xCC); _delay_us(50);   //Display on, cursor off, blink off

    i2c_write(0x0C); _delay_us(1700);  //clear display
    i2c_write(0x1C); _delay_us(1700);  //0x01

I know that each byte sent has the correct format (i.e. 0 0 1 DL N F X X ), but nothing was said regarding the ordering of such statements.

This sequence seemed most logical:

Funtion Set (4-bit)

Entry Mode (shifting, etc)

Commands (state variables)

Any ideas?

  • 1
    \$\begingroup\$ Are you sure the LCD has a "CS" pin and not a "E" pin? Normally this pin is toggled to clock in the commands and data. \$\endgroup\$ Mar 4, 2014 at 3:52
  • \$\begingroup\$ Interesting. Now that you mention it, another LCD that I have has this feature. Perhaps it's necessary to shift in data with CS low, then shift the same data with CS high to clock in the data. \$\endgroup\$
    – sherrellbc
    Mar 4, 2014 at 3:56
  • \$\begingroup\$ @sherrellbc On the product page, there is a link to the source code of the Arduino driver for this LCD via I2C. Did you base your code on that code? I gave it a quick look. I may be off, but what your code is doing looks different from what that code is doing. Look at methods LiquidCrystal_I2C::begin(...), LiquidCrystal_I2C::pulseEnable(...) and LiquidCrystal_I2C::write4bits(...) in LiquidCrystal_I2C.cpp. \$\endgroup\$ Mar 4, 2014 at 6:47

2 Answers 2

#define ON  1
#define OFF 0

//#define __LCD2__  // 2 row display
#define __LCD4__  // 4 row display

#ifdef __LCD2__
  #define LCD_MAX_LINES  2  // usually a 1602 2 X 16
  #define LCD_DISPLAY_WIDTH 16
  #define LCD_ID 0x4E       // I2C Base address for this interface

#ifdef __LCD4__
  #define LCD_MAX_LINES  4  // usually a J204A 4 X 20
  #define LCD_DISPLAY_WIDTH 20
  #define LCD_ID 0x40       // I2C Base address for this interface

#define RS          0b00000001  //P0 - PCF8574T Pin connected to RS
#define RW          0b00000010  //P1 - PCF8574T Pin connected to RW
#define EN          0b00000100  //P2 - PCF8574T Pin connected to EN
#define BACKLIGHT   0b00001000  //P3 - PCF8574T Pin connected to BACKLIGHT

#define LCD_LINE1   0x80        // LCD RAM address for line 1
#define LCD_LINE2   0xC0        // LCD RAM address for line 2
#define LCD_LINE3   0x94        // LCD RAM address for line 3
#define LCD_LINE4   0xD4        // LCD RAM address for line 4

int LcdBacklight = ON;

void InitLCD(void)
    printf("Initializing LCD...\r\n");

    delay_ms(500); //LCD power up delay


    //First state in 8 bit mode

    //Then set to 4-bit mode

    //mode 4 bit, 2 lines, characters 5 x 7

    //no need to have the cursor on. 
    //but if you want then '0Ch' is the addr

    //the cursor moves to the left (06h)

    printf("LCD   Initialized...\r\n");
  • 3
    \$\begingroup\$ I've formatted the code a bit but a description of how that solves the problem would be good. A few function calls seem to be either missing or compiler dependant. \$\endgroup\$
    – PeterJ
    Jul 25, 2014 at 10:46

There is a great c# implementation here: LiquidCrystal_I2C.cs


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.