Electronic – Debugging initialization of LCD with NT7605 driver

launchpadlcdmsp430

I've been trying to get my LCD initialized for about a week now, and am quite embarrassed to say that I've been unsuccessful thus far. I've done this in the past, and I remember it being a little tricky getting the initialization sequence just right, but at this point I think I've fully vetted the implementation and it's just not working.

Setup:

  1. NHT-C0220AZ-FSW-FTW LCD with an NT7605 driver
  2. TI Launchpad w/ MSP430G2231
  3. single-turn 10k pot for contrast control
  4. LCD powered with 3.3V
  5. Launchpad powered with USB
  6. Grounds for each component tied together
  7. using the LCD's 4bit interface
  8. LCD backlight connected to Vcc (3.3V) from Launchpad

enter image description here

Here are things I have done so far for testing:

  1. Double checked connections
    1. LCD pins D4-D7, RS, R/W, and E
    2. Potentiometer hooked up to contrast control pin, and I have verified that the voltage goes from 0 – Vdd.
    3. LCD Vdd hooked up to 3.4V, which is at about the minimum voltage spec
  2. Double checked I/O routines on MSP430
    1. LCD pins are reset/set as expected as I step through my code
    2. Timing routines are semi "calibrated" for loops
  3. Cross checked documentation for initialization routines against others' routines that I have found online
      1.

Yet after all of this, I can't get anything to display on the LCD! So here are my questions:

  1. The manufacturer has verified that there is a bug in the NT7605 where the busy bit isn't asserted properly. So I have been using fixed delays (fine with me), but wanted to use the busy flag to see if the driver is even responding to commands. Is there another way for me to do a low-level diagnostic to see what the LCD is thinking as I send initialization commands?
  2. Has anyone else here used the same LCD? All other standard LCDs I've used (2×20 character types) darken noticeably when I turn the contrast adjustment, and IIRC they do this even when not initialized properly. However, when I turn the pot on mine, the LCD doesn't darken at all. Perhaps this is because it's not initialized, but I'm not sure.
  3. Can anyone find something screwy with this initialization routine?
    1. delay > 30ms
    2. send 0x20, upper nibble only
    3. send 0x28 (set 4 bit interface)
    4. wait 10ms
    5. send 0x0C (display on, cursor off, blink off)
    6. wait 10ms
    7. send 0x01 (clear display)
    8. wait 10ms
    9. send 0x02 (increment cursor, no display shift)
    10. wait 10ms
    11. set RS high to start sending character data
    12. send 0x48 (display 'H')

Initialization routine from the manufacturer

My code looks like this:

void InitializeLcd()
{
    DelayTicks( 10000);
    // 4 bit interface, 2 lines, 5x8 characters
    // the spec sheet shows the 0x20 part of 0x28 getting sent an extra time
    // so I used a special function to deal with this case.  This just sends
    // the 0x20 part and ignores the 0x08 part.
    SendLcdUpperNibble( COMMAND, 0x28);
    SendLcdByte( COMMAND, 0x28);
    DelayTicks( 1000);
    // Display on, cursor off, blink off
    SendLcdByte( COMMAND, 0x0C);
    DelayTicks( 1000);
    // clear display
    ClearLcd();
    // Entry mode set - increment cursor, no display shift
    SendLcdByte( COMMAND, 0x02);
    DelayTicks( 1000);
    // Set write to DDRAM mode since we'll just be sending data from now on
    SendLcdByte( DATA, 0x48);
    SendLcdByte( DATA, 0x65);
    SendLcdByte( DATA, 0x6C);
    SendLcdByte( DATA, 0x6C);
    SendLcdByte( DATA, 0x6F);
}

void ClearLcd()
{
    // Clear display
    SendLcdByte( COMMAND, 0x01);
    DelayTicks( 1000);  
}

void SetRS( int value)
{
    if( value == 0)
        P2OUT &= ~RS;
    else
        P2OUT |= RS;
}

void SetRW( int value)
{
    if( value == 0)
        P2OUT &= ~RW;
    else
        P2OUT |= RW;    
}

void SetE( int value)
{
    if( value == 0)
        P1OUT &= ~E;
    else
        P1OUT |= E;
}

void DelayMs( int delay)
{
    int ctr;
    int ms = delay * 100;
    for( ctr=0; ctr<ms; ctr++);
}

void DelayTicks( int ticks)
{
    int ctr;
    for( ctr=0; ctr<ticks; ctr++);
}

void SendLcdByte( unsigned char command_0_or_data_1, unsigned char command)
{
    SendLcdUpperNibble( command_0_or_data_1, command);
    // send the lower nibble next
    // special thank you to ToyBuilder for catching my missed bit-shift in the following line
    // I also had the mask on P1OUT incorrect, presumably because I messed up the command mask and just made it match that.
    P1OUT = ((command & 0x0F) << 4) | (P1OUT & 0x0F);
    Strobe( command_0_or_data_1);
}

void SendLcdUpperNibble( unsigned char command_0_or_data_1, unsigned char upper_nibble)
{
    P1OUT = (upper_nibble & 0xF0) | (P1OUT & 0x0F);
    Strobe( command_0_or_data_1);
}

void Strobe( unsigned char command_0_or_data_1)
{
    SetRS( command_0_or_data_1);
    SetRW( 0);
    DelayTicks( 1000);
    SetE( 1);
    DelayTicks( 1000);
    SetE( 0);       
}

The only thing I can say is that the LCD looks like it flickers when I step over SendLcdByte and am sending it character data. When I scope everything, it sure looks like I'm flipping bits properly…

EDIT — I soldered up a new LCD, and this time I tried leaving the unused data pins (D0-D3) disconnected (i.e. floating). There was no difference. The LCD still flickers when I initialize. I am now waiting 100ms for all delays, including a delay when strobing E. I have also disconnected Vcc coming from the Launchpad FET section and am now just powering the MSP430 and LCD from my lab power supply.

EDIT #2 — I went to a 3.3V LCD and everything magically started working. Thanks to ToyBuilder for catching a stupid code bug when I was debugging with the 5V LCD. After the swap the LCD initialized properly. I'm currently displaying garbage instead of "Hello", but that's unrelated to this question.

EDIT #3 — found my display bug — I was sending 0x06 for entry mode instead of 0x02. Not sure why I did that, must have been a typo.

Best Answer

Oh, duh, I didn't read your code carefully -- your send SendLcdByte is wrong:

    void SendLcdByte( unsigned char command_0_or_data_1, unsigned char command)
{
    SendLcdUpperNibble( command_0_or_data_1, command);
    // send the lower nibble next
 // AS WRITTEN:
    P1OUT = (command & 0x0F) | (P1OUT & 0xF0);
 // SHOULD BE:
    P1OUT = ((command & 0x0F) << 4) | (P1OUT & 0xF0);
    Strobe( command_0_or_data_1);
}