Newhaven 4x40 Display Initialization - Lines 1 & 3 Solid

Discussion in 'Embedded Systems and Microcontrollers' started by andy.senn, May 17, 2016.

  1. andy.senn

    Thread Starter New Member

    May 17, 2016
    4
    1
    Hey, guys:

    First of all, I'm new here, so I'm very hopeful that I've found the right place to ask my question! :)

    I've been working on learning electronics on my own. I'm currently working on programming an Atmel MCU (ATmega88A) to control a Newhaven 4x40 character display (NHD-0440WH-ATMI-JT#). I've followed the specification as closely as I could, but after days of banging my head against the wall, certain that I was just doing something dumb, I've decided to ask for some help. I've found a couple of folks with similar problems, but the responses have not helped me much. I'm also trying to learn C in the process, so please let me know if you have any constructive criticism there, too.

    Please remember that I'm learning. I'm a Java engineer by day, so this is new territory to me. :)

    When I power it up, lines 1 and 3 of the display are solid, while lines 2 and 4 are blank. Here is what I have so far:

    lcd.h
    Code (Text):
    1. #ifndef LCD_H_
    2. #define LCD_H_
    3.  
    4.  
    5. #define LCD_DATA_DDR    DDRB
    6. #define LCD_CTRL_DDR    DDRD
    7.  
    8. #define LCD_DATA        PORTB
    9. #define LCD_CTRL        PORTD
    10.  
    11. #define LCD_E1            PIND0        // Operation Enable for Top 2 Lines
    12. #define LCD_RW            PIND1        // Read / Write (1/0)
    13. #define LCD_RS            PIND2        // Register Select (Command Register/Data Register)
    14. #define LCD_E2            PIND3        // Operation Enable for Bottom 2 Lines
    15.  
    16. #define DEBUG_LED        PINC5
    17.  
    18. #define LCD_CMD_CS        0b00000001    // Clear Screen
    19. #define LCD_CMD_HOME    0b00000010    // Return Cursor to Home Position
    20. #define LCD_CMD_DIR        0b00000100    // Set: Cursor Move Direction [ Pin 1 ], Display Shift [ Pin 0 ]
    21. #define LCD_CMD_PWR        0b00001000    // Set Display: Full [ Pin 2 ], Cursor [ Pin 1 ], [ Pin 0 ] Cursor Position
    22. #define LCD_CMD_SHIFT    0b00010000    // Set: Shift Control [ Pin 3 ], Cursor Move Direction (RTL/LTR) [ Pin 2 ]
    23. #define LCD_CMD_FUNC    0b00100000    // Set: Data Length (8/4 Bits) [ Pin 4 ], Line Number (2/1) [ Pin 3 ], Font Size (5x11/5x8) [ Pin 2 ]
    24. #define LCD_CMD_CGRAM    0b01000000    // Set: CGRAM Address [ Pins 5:0 ]
    25. #define LCD_CMD_DDRAM    0b10000000    // Set: DDRAM Address [ Pins 6:0 ]
    26.  
    27. #define LCD_COLS        40
    28. #define LCD_ROWS        4
    29.  
    30. void lcd_command ( int _command );
    31. void lcd_init ( void );
    32. void lcd_wait ( void );
    33. void lcd_write ( char *_text );
    34. void lcd_write_char ( unsigned char _char );
    35.  
    36. #endif /* LCD_H_ */
    lcd.c
    Code (Text):
    1. #include <asf.h>
    2. #include <util/delay.h>
    3. #include "lcd.h"
    4.  
    5. void lcd_command ( int _command ) {
    6.     lcd_wait();
    7.  
    8.     LCD_DATA = _command;
    9.     LCD_CTRL &= ~ 1 << LCD_RW;
    10.     LCD_CTRL &= ~ 1 << LCD_RS;
    11.  
    12.     lcd_wait();
    13.  
    14.     LCD_DATA = 0;
    15. }
    16.  
    17. void lcd_init ( void ) {
    18.     _delay_ms( 1000 ); // Specification >40mS
    19.     lcd_command( 0x3C );
    20.     _delay_us( 100 ); // Specification: >37uS
    21.     lcd_command( 0x3C );
    22.     _delay_us( 100 ); // Specification: >37uS
    23.     lcd_command( LCD_CMD_PWR + 0x07 );
    24.     _delay_us( 100 ); // Specification: >37uS
    25.     lcd_command( LCD_CMD_CS );
    26.     _delay_ms( 10 ); // Specification: >1.52mS
    27.     lcd_command( LCD_CMD_DIR + 0x02 );
    28. }
    29.  
    30. void lcd_wait ( void ) {
    31.     LCD_DATA_DDR = 0x00;
    32.  
    33.     LCD_CTRL |= 1 << LCD_RW;
    34.     LCD_CTRL &= ~ 1 << LCD_RS;
    35.  
    36.     while ( LCD_DATA > 0x80 ) {
    37.         LCD_CTRL |= 1 << LCD_E1 | 1 << LCD_E2;
    38.         asm volatile ( "nop" );
    39.         LCD_CTRL &= ~ 1 << LCD_E1 | 1 << LCD_E2;
    40.     }
    41.  
    42.     LCD_DATA_DDR = 0xFF;
    43. }
    44.  
    45. void lcd_write ( char *_text ) {
    46.     while ( *_text > 0 ) { lcd_write_char( *_text++ ); }
    47. }
    48.  
    49. void lcd_write_char ( unsigned char _char ) {
    50.     lcd_wait();
    51.  
    52.     LCD_DATA = _char;
    53.     LCD_CTRL &= ~ 1 << LCD_RW;
    54.     LCD_CTRL |= 1 << LCD_RS;
    55.  
    56.     lcd_wait();
    57.  
    58.     LCD_DATA = 0x00;
    59. }
    main.c
    Code (Text):
    1. #include <asf.h>
    2. #include "lcd/lcd.h"
    3.  
    4. int main ( void )
    5. {
    6.     board_init();
    7.  
    8.     DDRB = 0b11111111;
    9.     DDRC = 0b11111111;
    10.     DDRD = 0b11111111;
    11.  
    12.     lcd_init();
    13.  
    14.     lcd_write( "Hello, World!" );
    15.  
    16.     while ( 1 ) {
    17.      
    18.     }
    19. }
    I hate to drop a bunch of code on here, but I really don't know where the problem resides. I assume that I'm doing something wrong as early as 'lcd_init()' since lines 1 and 3 are still solid.

    Any help whatsoever would be very, very much appreciated!
     
  2. MrChips

    Moderator

    Oct 2, 2009
    12,440
    3,361
    This is a common result when the display is not initialized correctly. I have not looked into your code in full detail but here are some suggestions.

    Are you using 4-bit or 8-bit interface?
    A circuit schematic of your interface would be useful to examine for issues.

    Check to see where your code is ending up. Is it reaching the final while (1) loop?

    Replace the lcd_wait() function with a simple _delay_ms(10) for now.

    I have some code written in my MSP430 blog that you can examine.
    While this is for a different processor, the steps for initializing the LCD are shown.
    Note that this example uses a 4-bit interface.
     
  3. Sensacell

    Well-Known Member

    Jun 19, 2012
    1,130
    266
    I have experienced a similar problem in the past.
    If I remember correctly, the address of the 2nd line character position is not what you think it is- read the data sheet carefully, it jumps over a range in an awkward way - it's a bit counter-intuitive.
     
  4. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,387
    1,605
    I cannot follow your lcd_command Or lcd_write_char functions as you haven't included some symbols but I suspect the problem is in there as I do not see you exercising the E or clock line.

    One excellent first post though. You actually found the code tags and your code is well spaced and self documenting.

    You must do this stuff for a living. <g>

    Welcome to the forums!
     
    andy.senn likes this.
  5. dannyf

    Well-Known Member

    Sep 13, 2015
    1,806
    361
    That means the kcd isn't correctly initialized and your contrast is about right - a wonderful feature.

    I would check wiring and check code vs the data sheet.
     
  6. andy.senn

    Thread Starter New Member

    May 17, 2016
    4
    1
    Hey, guys:

    Thank you very much for your feedback. There are a few things that are wrong, and your comments helped bring those to light.

    In the end, I ended up just writing a bare-bones implementation of the LCD initialization as defined in the specification. My implementation looks like this:

    main.c
    Code (Text):
    1. #include <avr/io.h>
    2. #include <avr/portpins.h>
    3. #include <util/delay.h>
    4. #include "main.h"
    5.  
    6. int main( void )
    7. {
    8.     DDRB = 0b11111111; // Data
    9.     DDRD = 0b11111111; // Control
    10.    
    11.     _delay_ms( 15 );
    12.     command1( 0x30 );
    13.     command2( 0x30 );
    14.    
    15.     _delay_ms( 5 );
    16.     command1( 0x30 );
    17.     command2( 0x30 );
    18.    
    19.     _delay_ms( 5 );
    20.     command1( 0x30 );
    21.     command2( 0x30 );
    22.    
    23.     _delay_ms( 5 );
    24.     command1( 0x38 );
    25.     command2( 0x38 );
    26.    
    27.     command1( 0x08 );
    28.     command2( 0x08 );
    29.    
    30.     command1( 0x01 );
    31.     command2( 0x01 );
    32.    
    33.     command1( 0x06 );
    34.     command2( 0x06 );
    35.    
    36.     command1( 0x0C );
    37.     command2( 0x0C );
    38.    
    39.     _delay_ms( 10 );
    40.     writedata1( 'H' );
    41.     writedata1( 'e' );
    42.     writedata1( 'l' );
    43.     writedata1( 'l' );
    44.     writedata1( 'o' );
    45.     writedata1( ',' );
    46.     writedata1( ' ' );
    47.     writedata1( 'w' );
    48.     writedata1( 'o' );
    49.     writedata1( 'r' );
    50.     writedata1( 'l' );
    51.     writedata1( 'd' );
    52.     writedata1( '!' );
    53.    
    54.     _delay_ms( 10 );
    55.     writedata2( 'H' );
    56.     writedata2( 'e' );
    57.     writedata2( 'l' );
    58.     writedata2( 'l' );
    59.     writedata2( 'o' );
    60.     writedata2( ',' );
    61.     writedata2( ' ' );
    62.     writedata2( 'w' );
    63.     writedata2( 'o' );
    64.     writedata2( 'r' );
    65.     writedata2( 'l' );
    66.     writedata2( 'd' );
    67.     writedata2( ' ' );
    68.     writedata2( '2' );
    69.     writedata2( '!' );
    70.    
    71.    
    72.     while (1)
    73.     {
    74.        
    75.     }
    76. }
    77.  
    78. void command1( char i )
    79. {
    80.     PORTB = i;
    81.     PORTD |= 1 << PIND0;
    82.     _delay_ms( 2 );
    83.     PORTD &= ~ 1 << PIND0;
    84. }
    85.  
    86. void command2( char i )
    87. {
    88.     PORTB = i;
    89.     PORTD |= 1 << PIND6;
    90.     _delay_ms( 2 );
    91.     PORTD &= ~ 1 << PIND6;
    92. }
    93.  
    94. void writedata1( char i )
    95. {
    96.     PORTB = i;
    97.     PORTD |= 1 << PIND0 | 1 << PIND2;
    98.     _delay_ms( 2 );
    99.     PORTD &= ~ 1 << PIND0;
    100. }
    101.  
    102. void writedata2( char i )
    103. {
    104.     PORTB = i;
    105.     PORTD |= 1 << PIND6 | 1 << PIND2;
    106.     _delay_ms( 2 );
    107.     PORTD &= ~ 1 << PIND6;
    108. }
    This worked to initialize the first controller (the first 2 lines), but I'm still getting a solid 3rd line. Either way, this is definitely some much needed progress. :) I should have known to do this earlier.

    Thanks again for the feedback, guys. This simple accomplishment has re-motivated me to keep playing with this stuff. :)
     
  7. andy.senn

    Thread Starter New Member

    May 17, 2016
    4
    1
    And yes, @ErnieM. As a Senior Software Engineer, I've used forums like this before. I've just become a bit gun-shy thanks to the Stack Exchange sites. :)

    Thanks for your understanding. It's great to know that there's a community out there that is willing to help those that are just getting started.
     
  8. andy.senn

    Thread Starter New Member

    May 17, 2016
    4
    1
    I just figured out the issue with the 2nd controller. Since pins 12-14 on the display are power-related, I skipped those and wired E2 to PIND3, not PIND6. I was just being dumb. Thanks again, guys!
     
    ErnieM likes this.
Loading...