3
\$\begingroup\$

I have successfully implemented the I2C protocol necessary to communicate with the device, but I am absolutely stumped on the initialization sequence to get it to work. I have tried countless different sequences that I have found on various websites, different datasheets, and even sequences I just contrived myselfed.

Here is the specific device that I am using: I2C Backpack & LCD

On that same page is a link to the schematic of the I2C device where you can see that 4 data lines (therefore 4-bit), RS, RW, BackLight, and E-CLK are driven from the device output. I soldered the driver to the LCD screen and measured the voltage on each pin as I pass in data after addressing the device with address 0x27 to ensure the correct data is getting to the screen with the correct format. Since the Clk pin is driven as an output of the driver, it's necessary to shift in the data with the clock as HIGH, and then again as LOW. I simply cannot get this to work and am quite honestly at a point where I do not have any more ideas to try.

Assuming the I2C protocol works, which it does because I get ACKs from the driver after addressing and each byte sent, here is the code I have written to drive the screen.

 #define F_CPU 1000000
 #include <util/delay.h>
 #include "i2c.h"

#define I2C_DEL_T       100     //4uS
#define I2C_DEL()       (_delay_us(I2C_DEL_T))
#define I2C_READ        1
#define I2C_WRITE       0 
#define RW_BIT          0

 #define LCD_RS         0
 #define LCD_RW         1
 #define LCD_CLK        2
 #define LCD_BL         3

 #define COMMAND        0
 #define DATA           1
 #define LCD_READ       1
 #define LCD_WRITE      0
 #define BL_OFF         0
 #define BL_ON          1

 void lcdInit(void);
 void writeByteWithClock(uint8_t RS, uint8_t RW, uint8_t BL, uint8_t data);
 void writeNibbleWithClock(uint8_t RS, uint8_t RW, uint8_t BL, uint8_t data);


 //----------------------------------------------------------------------------
 void writeByteWithClock(uint8_t RS, uint8_t RW, uint8_t BL, uint8_t data){
uint8_t temp = data;    //init temp = data and overwrite lower nibble 

//upper nibble
temp &= 0xF0;           
temp |= ( (RS<<LCD_RS) | (RW<<LCD_RW) | (BL<<LCD_BL) | (1<<LCD_CLK) ); //set as sent RS, RW, BL, and CLK high  
i2c_write(temp);
I2C_DEL(); 
i2c_write( temp & ~(1<<LCD_CLK) );          //drive CLK bit low and send again
I2C_DEL(); 

//lower nibble 
temp &= 0x0F;                               //clear upper nibble and retain lower nibble (RS, RW, etc)
temp |= ( (data<<4) | (1<<LCD_CLK) ) ;      //set upper nibble same as data && drive CLK high
i2c_write(temp);
I2C_DEL();
i2c_write( temp & ~(1<<LCD_CLK) );          //drive CLK bit low and send again
I2C_DEL();
 }

 //----------------------------------------------------------------------------
 void writeNibbleWithClock(uint8_t RS, uint8_t RW, uint8_t BL, uint8_t data){
uint8_t temp = data;    //init temp = data and overwrite lower nibble
temp &= 0xF0;           //clear low nibble
temp |= ( (RS<<LCD_RS) | (RW<<LCD_RW) | (BL<<LCD_BL) | (1<<LCD_CLK) ); //set as sent - RS, RW, BL, and CLK high

i2c_write(temp);
I2C_DEL();
i2c_write( temp & ~(1<<LCD_CLK) );  //drive CLK bit low and send again
I2C_DEL();
 }

 //----------------------------------------------------------------------------
 void lcdInit(void){
_delay_ms(100); 

writeNibbleWithClock(COMMAND, LCD_WRITE, BL_ON, 0x30); _delay_us(4500);
writeNibbleWithClock(COMMAND, LCD_WRITE, BL_ON, 0x30); _delay_us(150);
writeNibbleWithClock(COMMAND, LCD_WRITE, BL_ON, 0x30); _delay_us(100);
writeNibbleWithClock(COMMAND, LCD_WRITE, BL_ON, 0x20); _delay_us(100);          //4-bit mode 

writeByteWithClock(COMMAND, LCD_WRITE, BL_ON, 0x28); _delay_us(100);            //N=1 (2 line), F=0 (5x8)
writeByteWithClock(COMMAND, LCD_WRITE, BL_ON, 0x08); _delay_us(100);            //Display off, Cursor Off, Blink off
writeByteWithClock(COMMAND, LCD_WRITE, BL_ON, 0x01); _delay_us(5000);           //clear
writeByteWithClock(COMMAND, LCD_WRITE, BL_ON, 0x06); _delay_us(100);            //ID=1(increment), S=0 (no shift)

writeByteWithClock(COMMAND, LCD_WRITE, BL_ON, 0x0C); _delay_us(100);            //Display on, Cursor Off, Blink off
 }

Sites I've sourced:

And countless datasheets.

Any ideas?

\$\endgroup\$
1
  • 1
    \$\begingroup\$ You can try this library. Just make sure to change the LCD pin mapping in lcdpcf8574.h to match the connections of your device \$\endgroup\$
    – alexan_e
    Mar 8, 2014 at 13:59

1 Answer 1

1
\$\begingroup\$

The lcd that you linked is based on a HD44780 display controller. Here is the initialization sequence. The I2C backpack is actually 4-Bit interfaced.
What you're doing wrong is:
writeNibbleWithClock(COMMAND, LCD_WRITE, BL_ON, 0x30); _delay_us(4500); writeNibbleWithClock(COMMAND, LCD_WRITE, BL_ON, 0x30); _delay_us(150); writeNibbleWithClock(COMMAND, LCD_WRITE, BL_ON, 0x30); _delay_us(100); writeNibbleWithClock(COMMAND, LCD_WRITE, BL_ON, 0x20); _delay_us(100);

What you must be doing is
writeNibbleWithClock(COMMAND, LCD_WRITE, BL_ON, 0x3); _delay_us(4500); writeNibbleWithClock(COMMAND, LCD_WRITE, BL_ON, 0x3); _delay_us(150); writeNibbleWithClock(COMMAND, LCD_WRITE, BL_ON, 0x3); _delay_us(100); writeNibbleWithClock(COMMAND, LCD_WRITE, BL_ON, 0x2); _delay_us(100);

Hope it helps !

\$\endgroup\$
2
  • \$\begingroup\$ The code for writeNibbleWithClock() only considers the higher nibble of the passed data. I should have written that function to use the lower nibble so you can pass data like you have shown. However, regardless, the function only writes a nibble. \$\endgroup\$
    – sherrellbc
    Mar 8, 2014 at 18:32
  • \$\begingroup\$ Can you try with writeByteWithClock(COMMAND, LCD_WRITE, BL_ON, 0x3); just to be sure. Also do try with more delay like instead of _delay_us(4500) try with _delay_ms(5) or even _delay_ms(10). Additionally I'd suggest(for testing/tuning purpose) you to define a TEST_DELAY #define TEST_DELAY 1 and replace all the _delay_us(100) with _delay_ms(TEST_DELAY) or _delay_ms(TEST_DELAY). After your lcd starts to show characters you can lower down the TEST_DELAY and eventually tune with _delay_us(TEST_DELAY) \$\endgroup\$
    – vyi
    Mar 8, 2014 at 19:49

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.