GDM1602K LCD HD44780U Interface

Does anyone have any clue why this code will not initialize the LCD? I’m out of ideas. This code is the umpteenth revision with no success.

;*******************************************************************************

;*******************************************************************************
            .cdecls C,LIST,"msp430x16x.h"  ; Include device header file
		
;-------------------------------------------------------------------------------
            .text                           ; Progam Start
;-------------------------------------------------------------------------------
RESET       mov.w   #0A00h,SP               ; Initialize stack pointer
StopWDT     mov.w   #WDTPW+WDTHOLD,&WDTCTL	; Stop WDT
			bis.b   #0ffh,&P1DIR			; P1.x output
			bis.b   #00fh,&P2DIR			; P2.(0-3) output
                                            ;
iniLCD		mov.w   #0528h,R15				; Set delay to 40ms (1320 cycles @32k Hz)
dec1		dec.w   R15                     ; Decrement R15
            jnz     dec1                    ; Delay done?
            
            mov.b	#00000000b,&P2OUT		; Function Set: RS(0), RW(0) (Write, ini E (low))
            mov.b	#00110000b,&P1OUT		; Function Set: DB(001110xx) (ini to 8-bit, sel 2 line disp,  5x8 char font)
            bis.b	#00000001b,&P2OUT		; Execute: E(1) (toggle E)
            nop
            nop
            nop
            nop
            nop
            nop
            nop
            nop
            nop
            nop
			bic.b	#00000001b,&P2OUT		; Execute: E(0) (toggle E)
			
			mov.w   #0084h,R15				; Set delay to 4.1ms (132 cycles @32k Hz)
dec2		dec.w   R15                     ; Decrement R15
            jnz     dec2                    ; Delay done?
			
			mov.b	#00000000b,&P2OUT		; Function Set: RS(0), RW(0) (Write, ini E (low))
            mov.b	#00110000b,&P1OUT		; Function Set: DB(001110xx) (ini to 8-bit, sel 2 line disp,  5x8 char font)
            bis.b	#00000001b,&P2OUT		; Execute: E(1) (toggle E)
            nop
            nop
            nop
            nop
            nop
            nop
            nop
            nop
            nop
			bic.b	#00000001b,&P2OUT		; Execute: E(0) (toggle E)
			
			mov.w   #0004h,R15				; Set delay to 100us (4 cycles @32k Hz)
dec3		dec.w   R15                     ; Decrement R15
            jnz     dec3                    ; Delay done?
            
            mov.b	#00000010b,&P2OUT		; Function Set: RW(1) (Read)
chkLCD0    	bis.b	#00000001b,&P2OUT		; Execute: E(1) (toggle E)
			nop
            nop
            nop
            nop
            nop
            mov.b	&P1IN,R10		; Busy?
            nop
            nop
            nop
            nop
			bic.b	#00000001b,&P2OUT		; Execute: E(0) (toggle E)
            bit.b	#10000000b,R10
            jnz		chkLCD0
            
            mov.b	#00000000b,&P2OUT		; Function Set: RS(0), RW(0) (Write, ini E (low))
            mov.b	#00111000b,&P1OUT		; Function Set: DB(001110xx) (ini to 8-bit, sel 2 line disp,  5x8 char font)
            bis.b	#00000001b,&P2OUT		; Execute: E(1) (toggle E)
            nop
			bic.b	#00000001b,&P2OUT		; Execute: E(0) (toggle E)
			bis.b	#00000010b,&P2OUT		; Function Set: RW(1) (Read)
chkLCD1    	bis.b	#00000001b,&P2OUT		; Execute: E(1) (toggle E)
			nop
            nop
            nop
            nop
            nop
            mov.b	&P1IN,R10		; Busy?
            nop
            nop
            nop
            nop
			bic.b	#00000001b,&P2OUT		; Execute: E(0) (toggle E)
            bit.b	#10000000b,R10
            jnz		chkLCD1
            
            mov.b	#00000000b,&P2OUT		; Function Set: RS(0), RW(0) (Write, ini E (low))
            mov.b	#00001000b,&P1OUT		; Function Set: DB(00001000) (Display Off)
            bis.b	#00000001b,&P2OUT		; Execute: E(1) (toggle E)
            nop
			bic.b	#00000001b,&P2OUT		; Execute: E(0) (toggle E)
			bis.b	#00000010b,&P2OUT		; Function Set: RW(1) (Read)
chkLCD2    	bis.b	#00000001b,&P2OUT		; Execute: E(1) (toggle E)
			nop
            nop
            nop
            nop
            nop
            mov.b	&P1IN,R10		; Busy?
            nop
            nop
            nop
            nop
			bic.b	#00000001b,&P2OUT		; Execute: E(0) (toggle E)
            bit.b	#10000000b,R10
            jnz		chkLCD2
            
            mov.b	#00000000b,&P2OUT		; Function Set: RS(0), RW(0) (Write, ini E (low))
            mov.b	#00000001b,&P1OUT		; Function Set: DB(00000001) (Display Clear)
            bis.b	#00000001b,&P2OUT		; Execute: E(1) (toggle E)
            nop
			bic.b	#00000001b,&P2OUT		; Execute: E(0) (toggle E)
			bis.b	#00000010b,&P2OUT		; Function Set: RW(1) (Read)
chkLCD3    	bis.b	#00000001b,&P2OUT		; Execute: E(1) (toggle E)
			nop
            nop
            nop
            nop
            nop
            mov.b	&P1IN,R10		; Busy?
            nop
            nop
            nop
            nop
			bic.b	#00000001b,&P2OUT		; Execute: E(0) (toggle E)
            bit.b	#10000000b,R10
            jnz		chkLCD3
            
            mov.b	#00000000b,&P2OUT		; Function Set: RS(0), RW(0) (Write, ini E (low))
            mov.b	#00000110b,&P1OUT		; Function Set: DB(00000110) (Entry Mode: inc, no disp shift)
            bis.b	#00000001b,&P2OUT		; Execute: E(1) (toggle E)
            nop
			bic.b	#00000001b,&P2OUT		; Execute: E(0) (toggle E)
			bis.b	#00000010b,&P2OUT		; Function Set: RW(1) (Read)
chkLCD4    	bis.b	#00000001b,&P2OUT		; Execute: E(1) (toggle E)
			nop
            nop
            nop
            nop
            nop
            mov.b	&P1IN,R10		; Busy?
            nop
            nop
            nop
            nop
			bic.b	#00000001b,&P2OUT		; Execute: E(0) (toggle E)
            bit.b	#10000000b,R10
            jnz		chkLCD4
            
            
            mov.b	#00000000b,&P2OUT		; Function Set: RS(0), RW(0) (Write, ini E (low))
            mov.b	#00001110b,&P1OUT		; Function Set: DB(00001110) (turn on display)
            bis.b	#00000001b,&P2OUT		; Execute: E(1) (toggle E)
            nop
			bic.b	#00000001b,&P2OUT		; Execute: E(0) (toggle E)
			bis.b	#00000010b,&P2OUT		; Function Set: RW(1) (Read)
chkLCD5    	bis.b	#00000001b,&P2OUT		; Execute: E(1) (toggle E)
			nop
            nop
            nop
            nop
            nop
            mov.b	&P1IN,R10		; Busy?
            nop
            nop
            nop
            nop
			bic.b	#00000001b,&P2OUT		; Execute: E(0) (toggle E)
            bit.b	#10000000b,R10
            jnz		chkLCD5
			mov.b	#00000100b,&P2OUT		; Function Set: RW(0) (Write)
            mov.b	#01001000b,&P1OUT		; Function Set: DB(01001000) (write 'H')
		    bis.b	#00000001b,&P2OUT		; Execute: E(1) (toggle E)
		    nop
			bic.b	#00000001b,&P2OUT		; Execute: E(0) (toggle E)
            mov.b	#00000010b,&P2OUT		; Function Set: RW(1) (Read)
chkLCD6    	bis.b	#00000001b,&P2OUT		; Execute: E(1) (toggle E)
			nop
            nop
            nop
            nop
            nop
            mov.b	&P1IN,R10		; Busy?
            nop
            nop
            nop
            nop
			bic.b	#00000001b,&P2OUT		; Execute: E(0) (toggle E)
            bit.b	#10000000b,R10
            jnz		chkLCD6
endloop		xor.b	#0fh,&P6OUT
 	        jmp		endloop

;--------------------------------------------------------------------------------
;           Interrupt Vectors
;--------------------------------------------------------------------------------
            .sect   ".reset"                ; MSP430 RESET Vector
            .short  RESET                   ;
            
            .end

I’m trying to run this off of the OLIMEX msp430 proto board (simplest, just RS232) and powering the lcd off of 5v on 16->15 and 2->1. The code is drawn out to make sure that no preprocessing/optimization could be introducing problems.

You do not appear to be changing P1 to an input when attempting to read the LCD busy flag.

So can I just change the direction right before testing it and then change it back right after?

The MCLK is probably 0.7 MHz (not 32 kHz) and it takes 3 MCLKs per loop. I think all your delays are too short.

P1DIR should be 0x00 most of the time. Only when R/W is 0 and E is 1, you first load P1OUT and then change P1DIR to 0xFF. After that, you change E to 0, and then change P1DIR back to 0x00.

OldCow:
The MCLK is probably 0.7 MHz (not 32 kHz) and it takes 3 MCLKs per loop. I think all your delays are too short.

P1DIR should be 0x00 most of the time. Only when R/W is 0 and E is 1, you first load P1OUT and then change P1DIR to 0xFF. After that, you change E to 0, and then change P1DIR back to 0x00.

Thanks. I’ll try that.

Does the E cycle (E high time) need to be 250ms? If so, where is the documentation are people finding that?

I think min. E high time is 250 nano-seconds, not 250 micro-seconds.

For your refrence, here is my demo code in c.

#include <MSP430x13x.h>
//
// Hardware initializations
//
void Init_HW(void)
{
//
// [Watchdog Timer]
//
WDTCTL=0x5A00 | 0x80;
//
// [Port 1/2]
//
P1OUT=P1IN;
P1DIR=0xFF;
P2OUT=P2IN & ~0x01; //P2.0 is LCD_E
P2DIR=0xFF;
//
// [Port 3/4]
//
// P3DIR=0x00; //P3.x are LCD_DBx
P4OUT=P4IN & ~0x18; //P4.4 is LCD_R/W, P4.3 is LCD_RS
P4DIR=0xFF;
//
// [Port 5/6]
//
P5OUT=P5IN;
P5DIR=0xF8; //P5.2, P5.1, P5.0 are push buttons
P6OUT=P6IN;
P6DIR=0xFF;
}
//
// write lcd instruction register
//
void wr_lcd_ir(int inst)
{
P4OUT&=~0x18; //R/W=Wr, RS=Ir
P2OUT|=0x01; //set E
P3OUT=inst; //load DB
P3DIR=0xFF; //drive DB
P2OUT&=~0x01; //clear E
P3DIR=0x00; //float DB
}
//
// write lcd data register
//
void wr_lcd_dr(char data)
{
P4OUT&=~0x10; //R/W=Wr
P4OUT|=0x08; //RS=Dr
P2OUT|=0x01; //set E
P3OUT=data; //load DB
P3DIR=0xFF; //drive DB
P2OUT&=~0x01; //clear E
P3DIR=0x00; //float DB
P4OUT&=~0x18; //R/W=Wr, RS=Ir
}
//
// read lcd status register
//
int rd_lcd_sr(void)
{
P4OUT|=0x10; //R/W=Rd
P4OUT&=~0x08; //RS=Sr
P2OUT|=0x01; //set E
int status=P3IN; //read status
P2OUT&=~0x01; //clear E
P4OUT&=~0x18; //R/W=Wr, RS=Ir
return (status);
}
//
// initialise lcd
//
void init_lcd(void)
{
__delay_cycles(20000); // ~20000us @ ~1MHz
wr_lcd_ir(0x30);
__delay_cycles(5500); // ~5500us @ ~1MHz
wr_lcd_ir(0x30);
__delay_cycles(150); // ~150us @ ~1MHz
wr_lcd_ir(0x30);
while ((rd_lcd_sr()&0x80)!=0) {};
wr_lcd_ir(0x38); //8-bit, 2-line, 5x8
while ((rd_lcd_sr()&0x80)!=0) {};
wr_lcd_ir(0x01); //clear-display
while ((rd_lcd_sr()&0x80)!=0) {};
wr_lcd_ir(0x0C); //display-on, cursor-off, blink-off
while ((rd_lcd_sr()&0x80)!=0) {};
wr_lcd_ir(0x06); //increment, shift-off
}
//
// display string
//
void display_string(char * str, int cnt)
{
for (int i=0; i<cnt; i++)
wr_lcd_dr(str[i]);
}
//
// Main routine
//
void main(void)
{
Init_HW(); //initialize MCU
init_lcd(); //initialize lcd
display_string("Hello!",6);
for (;;) {};
}

[/quote]

Thanks. I’ve tried porting it to my hardware config (I have p1 as the db bus and p2 (0->2) as E,R/W,and RS) with no success. Here is my latest attemp that tries to initialize by instruction since I have independent power supplies. This still doesn’t work :cry: . What the hell am I doing wrong?

;*******************************************************************************

;*******************************************************************************
            .cdecls C,LIST,"msp430x16x.h"  ; Include device header file
		
;-------------------------------------------------------------------------------
            .text                           ; Progam Start
;-------------------------------------------------------------------------------
RESET       mov.w   #0A00h,SP               ; Initialize stack pointer
StopWDT     mov.w   #WDTPW+WDTHOLD,&WDTCTL	; Stop WDT
			bic.b   #0ffh,&P1DIR			; P1.x set as input
			bis.b   #07h,&P2DIR				; P2 set as output

			bic.b	#04h,&P2OUT				; RS low
			mov.b	#030h,R10				; Load Function Set (Interface 8-bit)
			call	#LCD_EXEC
			
;			mov		60000,R14				; Delay
;DEL_0		dec		R14						; Delay
;			jnz		DEL_0					; Delay

;			mov.b	#030h,R10				; Load Function Set (Interface 8-bit)
;			call	#LCD_EXEC
			
;			mov		6000,R14				; Delay
;DEL_1		dec		R14						; Delay
;			jnz		DEL_1					; Delay
			
;			mov.b	#030h,R10				; Load Function Set (Interface 8-bit)
;			call	#LCD_EXEC
			
;			mov		600,R14					; Delay
;DEL_2		dec		R14						; Delay
;			jnz		DEL_2					; Delay
			
			mov.b	#038h,R10				; Load Function Set (Interface 8-bit)
			call	#LCD_EXEC
			mov.b	#08h,R10				; Load Display Off
			call	#LCD_EXEC
			mov.b	#01h,R10				; Load Display Clear
			call	#LCD_EXEC
			mov.b	#06h,R10				; 
			call	#LCD_EXEC
			mov.b	#030h,R10				; 
			call	#LCD_EXEC
			mov.b	#00Eh,R10				; 
			call	#LCD_EXEC
			mov.b	#006h,R10				; 
			call	#LCD_EXEC
			bis.b	#04h,&P2OUT				; RS high
			mov.b	#048h,R10				; 
			call	#LCD_EXEC
			
			
			
			
			
			
endloop		xor.b	#0fh,&P2OUT
 	        jmp		endloop
			

;///////////// Functions /////////////////////////////////////////////////////////////
			
LCD_EXEC:	bic.b	#02h,&P2OUT				; RW low, RS already set/clear
			nop
			bis.b	#01h,&P2OUT				; E high
			nop
			mov.b	R10,&P1OUT				; Load out P1 (expecting argument at R10)
			bis.b   #0ffh,&P1DIR			; P1.x set as output
			mov		183500,R15				; Set Delay of 250ms
DEC1		dec		R15
			jnz		DEC1
			bic.b	#01h,&P2OUT				; E Line Low
			bic.b   #0ffh,&P1DIR			; P1.x set as input
			call	#LCD_WAIT				; Wait for operation to complete
			ret
		
		
LCD_WAIT:	mov.b	#02h,&P2OUT				; RW high
			nop
			bis.b	#01h,&P2OUT				; E Line High
			nop
WAIT_MORE	mov.b	&P1IN,R11				; Move P1 into R11
			bit		#080h,R11				; Busy Flag Set?
			jnz		WAIT_MORE				; Loop if Busy
			mov.b	#00h,&P2OUT				; Clear Pin 2
			ret
			


;--------------------------------------------------------------------------------
;           Interrupt Vectors
;--------------------------------------------------------------------------------
            .sect   ".reset"                ; MSP430 RESET Vector
            .short  RESET                   ;
            
            .end

Independent power supply? Is the LCD on 5V and the MSP430 on 3.3V? If so, how do you connect RS, RW, E, and DBx with P2 and P3? See my post in the “Projects” Forum.

How about the contrast control? What do you use.

If there is no problem in hardware. This should work for you.

;******************************************************************************* 

;******************************************************************************* 
            .cdecls C,LIST,"msp430x16x.h"  ; Include device header file 
       
;------------------------------------------------------------------------------- 
            .text                           ; Progam Start 
;------------------------------------------------------------------------------- 
RESET       mov.w   #0A00h,SP               ; Initialize stack pointer 
StopWDT     mov.w   #WDTPW+WDTHOLD,&WDTCTL  ; Stop WDT 
            bic.b   #07h,&P2OUT             ; make sure RS, RW, and E are 0 
            bis.b   #07h,&P2DIR             ; and then enable outpu

            mov.b   #030h,R10               ; (DL 8-bit) 
            call    #LCD_EXEC 
 
            mov.b   #030h,R10               ; repeat
            call    #LCD_EXEC 
  
            mov.b   #030h,R10               ; repeat 
            call    #LCD_EXEC 
           
            mov.b   #038h,R10               ; (DL=8-bit, N=2-line, F=5x8) 
            call    #LCD_EXEC
 
            mov.b   #01h,R10                ; (clear display) 
            call    #LCD_EXEC
 
            mov.b   #0Ch,R10                ; (D=on, C=off, B=off) 
            call    #LCD_EXEC
 
            mov.b   #06h,R10                ; (I/D=inc, S=off)
            call    #LCD_EXEC 

            bis.b   #04h,&P2OUT             ; RS(1) send data now          
          
            mov.b   #41h,R10                ; "A"
            call    #LCD_EXEC 
          
            mov.b   #42h,R10                ; "B"
            call    #LCD_EXEC 
           
            mov.b   #43h,R10                ; "C"
            call    #LCD_EXEC 
           
            mov.b   #31h,R10                ; "1"
            call    #LCD_EXEC 
           
            mov.b   #32h,R10                ; "2"
            call    #LCD_EXEC 
          
            mov.b   #33h,R10                ; "3"
            call    #LCD_EXEC 
          
endloop     jmp     endloop 
          

;///////////// Functions ///////////////////////////////////////////////////////////// 
          
LCD_EXEC:   mov,w   #10000,R15              ; 3x10000 cycles @ 1MHz is 30 ms

wait        dec.w   R15                     ; this takes 1 cycle
            jnz     wait                    ; this takes 2 cycles 

            bis.b   #01h,&P2OUT             ; E high 

            mov.b   R10,&P1OUT              ; Load out P1 (expecting argument at R10) 
            bis.b   #0ffh,&P1DIR            ; P1.x set as output 
            bic.b   #01h,&P2OUT             ; E Low 
            bic.b   #0ffh,&P1DIR            ; P1.x set as input 

            ret 

;-------------------------------------------------------------------------------- 
;           Interrupt Vectors 
;-------------------------------------------------------------------------------- 
            .sect   ".reset"                ; MSP430 RESET Vector 
            .short  RESET                   ; 
            
            .end

Thanks again. I have all 8 pins of pin1 as my db bus. E,RW,RS,and V0 (although it isn’t used by the mcu) are pins 2.0 through 2.3, respectively. Signals are driven by the msp430 (including mode lines) while the lcd backlight and circuitry are powered by an independent power supply of 5V. For contrast, I just have a resister from V0 to ground of the 5V power supply, the power supply that does not share a common ground with the mcu board (which I realize now might be problem).

I will try this code and let you know. In the latest testing, I’ve noticed that the code I posted stayed in WAIT_MORE as the busy flag never cleared. I’m not sure why.

OldCow,

So, after trying your modified code and finally properly adjusting the contrast I have come to the following conclusions:

When I first ran your code, it would only get the top row to light up solid (all boxes completely on). So i played with it, made sure that my bus wasn’t plugged in backwards, etc. After realizing that the contrast adjustment could be the source of yet another problem I refaced the resistor with a 100k pot and Voila! It works. Regardless of whether or not the pot was a problem, your code was to first to get the top row to light up (which I now realize indicates a properly initialized lcd with improper contrast adjustment).

This ordeal for me has been a frustrating step in a much bigger project. This lcd is a small, but crucial component in a device that is being used in biomedical research. It’s one of those steps that’s ridiculously simple, but crucial when engineering a device from scratch under a strict time line. Your help has greatly helped California State University of Sacramento and Shriners Hospital of Northern California in the development of an automated fall detection system for children suffering from Cerebral Palsy. My work is in developing an automated neural net to intelligently detect falls in children. The device will be used by physicians to assess the efficacy of treatments for spastic diplegia (a type of CP).

Getting over this stumbling block allows me to focus on testing my neural net and get my work done on time. Thank you so much. Would you please PM me your contact info so I can credit you as a reference in the conference publications?