Help getting an LCD to work

I have an Optrex LCD (DMC-20481NY-LY-AGE) that is 4x20 characters and driven by a Microchip PIC16F877 running at 20MHz. I know I got this exact same physical LCD to work before but for the life of me I can't recall what trick I used to do so. Attached at the end is my software. I get power to the LCD, but all I see is lines 1 and 3 as all dark and lines 2 and 4 as all clear. Hunting around newsgroups leads me to think my initialization routines aren't working (gee, ya think?!?!) but as near as I can tell I have met or exceeded all of the timing requirements for data transfer. PLEASE HELP!!!!! If it matters, I am using a dedicated 5V DC supply to drive both the PIC and the LCD. The PIC is connected to the LCD through 330 Ohm resistors, with 10KOhm pulldown resistors to ground on ALL of the lines on the PIC side. This was because I was seeing a lot of glitches on powerup due to ports being inputs. Each line also has a .01uF cap to ground and there is a bypass capacitor on the 5V line to ground next to the PIC. The BusyFlag is also connected directly from the LCD to the PIC on PORTB, 6. Thanks for any insight!

-Will

; LCD Control Software ; ; Software uses a 20MHz crystal ; for timing. ;

;****************************************************************** Stall MACRO LOCAL Stall_Jump goto Stall_Jump Stall_Jump ENDM ;****************************************************************** Wait_For_Busy_Flag MACRO btfsc BUSY_FLAG goto $-1 ENDM ;****************************************************************** Wait_15ms MACRO LOCAL OuterLoop LOCAL InnerLoop

movlw .59 movwf OUTER_COUNTER OuterLoop movlw .255 movwf INNER_COUNTER InnerLoop Stall decfsz INNER_COUNTER, F goto InnerLoop decfsz OUTER_COUNTER, F goto OuterLoop ENDM ;****************************************************************** Wait_4.1ms MACRO LOCAL OuterLoop LOCAL InnerLoop

movlw .17 movwf OUTER_COUNTER OuterLoop movlw .255 movwf INNER_COUNTER InnerLoop Stall decfsz INNER_COUNTER, F goto InnerLoop decfsz OUTER_COUNTER, F goto OuterLoop ENDM ;****************************************************************** Wait_100us MACRO LOCAL InnerLoop

movlw .100 movwf INNER_COUNTER InnerLoop Stall decfsz INNER_COUNTER, F goto InnerLoop ENDM ;******************************************************************

list p=16F877

; Include file, change directory if needed include "p16f877.inc"

#define ENABLE PORTE, 2 #define RS PORTE, 1 #define RW PORTE, 0

#define DATA_PORT PORTD #define BUSY_FLAG PORTB, 6

OUTER_COUNTER equ 0x20 INNER_COUNTER equ 0x21

W_TEMP equ 0x70 STATUS_TEMP equ 0x71 PCLATH_TEMP equ 0x72

;//Reset Vector Org 0x00 clrf PCLATH ; ensure page bits are cleared goto Initialize

;//Interrupt Vector ORG 0x04 MOVWF W_TEMP ;Copy W to TEMP register SWAPF STATUS,W ;Swap status to be saved into W CLRF STATUS ;bank 0, regardless of current bank, Clears IRP,RP1,RP0 MOVWF STATUS_TEMP ;Save status to bank zero STATUS_TEMP register MOVF PCLATH, W ;Only required if using pages 1, 2 and/or 3 MOVWF PCLATH_TEMP ;Save PCLATH into W CLRF PCLATH ;Page zero, regardless of current page

;Fill this in if you want interrupt vectoring

banksel PCLATH_TEMP MOVF PCLATH_TEMP, W ;Restore PCLATH MOVWF PCLATH ;Move W into PCLATH SWAPF STATUS_TEMP,W ;Swap STATUS_TEMP register into W ;(sets bank to original state) MOVWF STATUS ;Move W into STATUS register SWAPF W_TEMP,F ;Swap W_TEMP SWAPF W_TEMP,W ;Swap W_TEMP into W retfie ; return from interrupt

;//Initialization Initialize clrf INTCON clrf INTCON CGIE bcf INTCON, GIE btfsc INTCON, GIE goto CGIE

; //Declare port/pin definitions banksel TRISA movlw B'00000111' movwf ADCON1 ; Port A is all digital movlw B'00000000' movwf TRISA ; Port A is OOOOOOOO movlw B'01000000' movwf TRISB ; Port B is OIOOOOOO movlw B'10000001' movwf TRISC ; Port C is IOOOOOOI movlw B'00000000' movwf TRISD ; Port D is OOOOOOOO bcf TRISE, PSPMODE ; Turn off the parallel port bcf TRISE, 0 ; Port E is -----OOO bcf TRISE, 1 bcf TRISE, 2

bsf OPTION_REG, 7 ;Turn off port B pullups

banksel OUTER_COUNTER bsf PORTB, 7

Wait_15ms Wait_15ms

bcf PORTB, 7

bcf RS bcf RW movlw b'00111000' call StrobeData

Wait_4.1ms Wait_4.1ms

bcf RS bcf RW movlw b'00111000' call StrobeData

Wait_4.1ms Wait_4.1ms

bcf RS bcf RW movlw b'00111000' call StrobeData

Wait_4.1ms Wait_4.1ms

call DisplayOFF_CursorOFF_BlinkOFF Wait_15ms Wait_4.1ms

call DisplayON_CursorON_BlinkON Wait_15ms Wait_4.1ms

call EntryModeSet Wait_100us

call ClearDisplay Wait_15ms Wait_4.1ms

movlw b'01001000' ;H call SendChar movlw b'01100101' ;e call SendChar movlw b'01101100' ;l call SendChar movlw b'01101100' ;l call SendChar movlw b'01101111' ;o call SendChar movlw b'01010111' ;W call SendChar movlw b'01101111' ;o call SendChar movlw b'01110010' ;r call SendChar movlw b'01101100' ;l call SendChar movlw b'01100100' ;d call SendChar

Eternal bcf PORTB, 0 nop bsf PORTB, 0 goto Eternal ;----------- StrobeData nop bsf ENABLE nop movwf DATA_PORT nop bcf ENABLE return ;----------- EntryModeSet btfsc BUSY_FLAG goto EntryModeSet bcf RS bcf RW movlw b'00000110' call StrobeData return ;----------- SendChar btfsc BUSY_FLAG goto SendChar bsf RS bcf RW call StrobeData return ;----------- ClearDisplay btfsc BUSY_FLAG goto ClearDisplay bcf RS bcf RW movlw 0x01 call StrobeData return ;----------- HomeCursor btfsc BUSY_FLAG goto HomeCursor bcf RS bcf RW movlw 0x02 call StrobeData return ;----------- DisplayOFF_CursorOFF_BlinkOFF btfsc BUSY_FLAG goto DisplayOFF_CursorOFF_BlinkOFF bcf RS bcf RW movlw b'00001000' call StrobeData return ;----------- DisplayOFF_CursorOFF_BlinkON btfsc BUSY_FLAG goto DisplayOFF_CursorOFF_BlinkON bcf RS bcf RW movlw b'00001001' call StrobeData return ;----------- DisplayOFF_CursorON_BlinkOFF btfsc BUSY_FLAG goto DisplayOFF_CursorON_BlinkOFF bcf RS bcf RW movlw b'00001010' call StrobeData return ;----------- DisplayOFF_CursorON_BlinkON btfsc BUSY_FLAG goto DisplayOFF_CursorON_BlinkON bcf RS bcf RW movlw b'00001011' call StrobeData return ;----------- DisplayON_CursorOFF_BlinkOFF btfsc BUSY_FLAG goto DisplayON_CursorOFF_BlinkOFF bcf RS bcf RW movlw b'00001100' call StrobeData return ;----------- DisplayON_CursorOFF_BlinkON btfsc BUSY_FLAG goto DisplayON_CursorOFF_BlinkON bcf RS bcf RW movlw b'00001101' call StrobeData return ;----------- DisplayON_CursorON_BlinkOFF btfsc BUSY_FLAG goto DisplayON_CursorON_BlinkOFF bcf RS bcf RW movlw b'00001110' call StrobeData return ;----------- DisplayON_CursorON_BlinkON btfsc BUSY_FLAG goto DisplayON_CursorON_BlinkON bcf RS bcf RW movlw b'00001111' call StrobeData return ;----------- END

Reply to
Will
Loading thread data ...

Hi, the 2 dark lines means that the module has not been initialised. Remove all the components from the connections to the module, just connect directly.

Reply to
CBarn24050

Hi again, i just noited that your "strobe data" is too fast, check the data sheet for timming, also your should put the data on the port before the enable pulse.

Reply to
CBarn24050

[...]

10nF on each signal line is quite a lot! Why do you need such a big capacitive load on the data wires?

Have you checked the timing on a scope, or are you just counting clock cycles in your program?

--
Cheers
Stefan
Reply to
Stefan Heinzmann

Make sure you have the proper delays in the Init routines. I've used the same display and had problems with short delays in the Init routines.

Cheers

Reply to
Martin Riddle

I can only tell you from my experience which things made my life difficult with LCD.

  1. Contrast voltage had to be negative.

I belive it isn't the case in your case, you only have to connect 10k potentiometer for contrast.

  1. Inpropper initialization routine.

Wrong sequence of initialization commands. If order off commands is not right it can cause a lot of headaches.

  1. Using BUSY flag?

When using BUSY flag you have to watch carefuly during the initialization routine when the busy flag can be checked.

In your case my guess you would be you have incorrect initialization routine maybe timings are ok but the order of commands isn't. I had done initialization as written in one datasheet of my 2x16 LCD, and it worked badly sometimes it would initialize the LCD, and sometimes wouldn't I found another sequence for initializing on the Internet and it worked great since then.

Mickey

Reply to
Mickey

Your strobedata routine is too fast. Many LCD displays have a cycle time of

500ns to 1000ns, where the E has to be kept high for 300 to 500ns or longer. Apart from that, your filtering of the datalines kills your signals. 0.01uF and 330 Ohm has a time constant of 3.3us. Your signals in the order of 1us cycle times will NEVER pass this filter. Remove the caps and resistors and you'll be fine.

Meindert

Reply to
Meindert Sprang

Reply to
Crooksie

I think one pin on the most PICs is open collector.

Reply to
CWatters

I'm not sure how you're arriving at that conclusion. The formula I used to determine how long the enable pin strobed was as follows: For a PIC

20 MHz external resonator/crystal -> 5MHz instruction rate (clock/4)

-> 200 ns per instruction.

Even assuming worst case that the PIC sets the pin high at the very end of the BSF instruction and low at the very beginning of the BCF instruction, there are 3 instructions between them. At 200ns each, that's at least 600ns and possibly 800ns if everything lines up nicely. I've also checked it with a scope probe and it looks more than long enough. In fact, I have verified that the PIC is in fact sending the signals I thinnk it should be at the right timing, based upon the datasheet that Optrex had on their website. In case anyone cares, that file was Dmcman_full.pdf and had 58 pages. It had no revisions listed on the second page so I guess it was revision 0.

Reply to
Will

(Maybe it's obvious from your code .... but I didn't read it.) The first thing I'd do is get rid of all the pulldowns and caps; you can add 'em all later if you really-really have to. I've driven half a dozen different LCDs with three kinds of PICs for several years and never needed all that extra hardware.

The most persistant bug in my LCD boilerplate setup routines is that it's 5x8 dots, 2x20 display and the LCD I've got hooked up is different from those. I recall being in the same boat as you are now ... for days! ... gnashing my teeth because I _knew_ the code worked (I was looking at at earlier project that used the same code), and I _knew_ the LCD was OK (because it worked when hooked up to a different project). Yes, it was a case of operator error; the display that wouldn't initialize was not a 2x20 but a 1x16.

Reply to
Michael

Ah yes ... the famous open collector gotcha. That's another trap for amateurs. It still bites me from time to time, even after upteen Microchip projects.

Reply to
Michael

yes well your right on the margin, if I were you I would put the extra nop in you can allways remove it later after you have everthing working.

Reply to
CBarn24050

of

longer.

By reading the datasheets and experience. Driving earlier LCD's from a '51 bus was already a problem. You had to use nifty adressing tricks to get it running as a memory mapped device. the other solution was to drive the port pins directly.

But I strongly suggest to remove the caps. Your signals do not have the proper rise and fall time requirements. And they simply block a strobe as as short as a microsecond.

Meindert

Reply to
Meindert Sprang

Ok, I've had limited success so far. Circuit-wise I have removed the capacitors from the data lines but left the series and pulldown resisitors alone. Program-wise I have added enourmous delays to the initialization routines and reordered some of the commands. The combination seems to have done the trick for initializing the display since I now get a blinking cursor and some letters. I say some letters, because there is still a timing glitch I can't seem to track down. I know it has to do with trying to use the Busy Flag instead of hard coded delays, but despite searching the web and pouring over cryptic datasheets I cannot find a solution that works. If someone familiar with PIC assembly could post a WORKING snippet of code for a

20MHz crystal, or if someone could just post a graphical plot of signals versus time for checking the busy flag I would greatly appreciate it! My new code is appended below. Thanks for all the help!

-Will

; LCD Control Software ; ; Software uses a 20MHz crystal ; for timing. ;

;****************************************************************** Stall MACRO LOCAL Stall_Jump goto Stall_Jump Stall_Jump ENDM ;****************************************************************** Wait_15ms MACRO LOCAL OuterLoop LOCAL InnerLoop

movlw .59 movwf OUTER_COUNTER OuterLoop movlw .255 movwf INNER_COUNTER InnerLoop Stall decfsz INNER_COUNTER, F goto InnerLoop decfsz OUTER_COUNTER, F goto OuterLoop ENDM ;****************************************************************** Wait_4.1ms MACRO LOCAL OuterLoop LOCAL InnerLoop

movlw .17 movwf OUTER_COUNTER OuterLoop movlw .255 movwf INNER_COUNTER InnerLoop Stall decfsz INNER_COUNTER, F goto InnerLoop decfsz OUTER_COUNTER, F goto OuterLoop ENDM ;****************************************************************** Wait_100us MACRO LOCAL InnerLoop

movlw .100 movwf INNER_COUNTER InnerLoop Stall decfsz INNER_COUNTER, F goto InnerLoop ENDM ;****************************************************************** CheckBusyFlag MACRO LOCAL JumpPoint JumpPoint bcf RS bsf RW nop nop bsf ENABLE nop nop nop nop nop bcf ENABLE btfsc BUSY_FLAG goto JumpPoint ENDM ;****************************************************************** list p=16F877

; Include file, change directory if needed include "p16f877.inc"

#define ENABLE PORTE, 2 #define RS PORTE, 1 #define RW PORTE, 0

#define DATA_PORT PORTD #define BUSY_FLAG PORTB, 6

OUTER_COUNTER equ 0x20 INNER_COUNTER equ 0x21

W_TEMP equ 0x70 STATUS_TEMP equ 0x71 PCLATH_TEMP equ 0x72

;//Reset Vector Org 0x00 clrf PCLATH ; ensure page bits are cleared goto Initialize

;//Interrupt Vector ORG 0x04 MOVWF W_TEMP ;Copy W to TEMP register SWAPF STATUS,W ;Swap status to be saved into W CLRF STATUS ;bank 0, regardless of current bank, Clears IRP,RP1,RP0 MOVWF STATUS_TEMP ;Save status to bank zero STATUS_TEMP register MOVF PCLATH, W ;Only required if using pages 1, 2 and/or 3 MOVWF PCLATH_TEMP ;Save PCLATH into W CLRF PCLATH ;Page zero, regardless of current page

;TO DO: Fill in for interrupt vectoring

banksel PCLATH_TEMP MOVF PCLATH_TEMP, W ;Restore PCLATH MOVWF PCLATH ;Move W into PCLATH SWAPF STATUS_TEMP,W ;Swap STATUS_TEMP register into W ;(sets bank to original state) MOVWF STATUS ;Move W into STATUS register SWAPF W_TEMP,F ;Swap W_TEMP SWAPF W_TEMP,W ;Swap W_TEMP into W retfie ; return from interrupt

;//Initialization from powerup Initialize clrf INTCON clrf INTCON CGIE bcf INTCON, GIE btfsc INTCON, GIE goto CGIE clrf INTCON

; //Declare port/pin definitions banksel TRISA movlw B'00000111' movwf ADCON1 ; Port A is all digital movlw B'00000000' movwf TRISA ; Port A is OOOOOOOO movlw B'01000000' movwf TRISB ; Port B is OIOOOOOO movlw B'10000001' movwf TRISC ; Port C is IOOOOOOI movlw B'00000000' movwf TRISD ; Port D is OOOOOOOO bcf TRISE, PSPMODE ; Turn off the parallel port bcf TRISE, 0 ; Port E is -----OOO bcf TRISE, 1 bcf TRISE, 2 bsf OPTION_REG, 7 ;Turn off port B pullups

banksel PORTB call Big_Delay call Big_Delay call Big_Delay call Big_Delay

banksel OUTER_COUNTER bsf PORTB, 7

Wait_15ms Wait_15ms

bcf PORTB, 7

bcf RS bcf RW movlw b'00111000' call StrobeData

Wait_15ms Wait_15ms

bcf RS bcf RW movlw b'00111000' call StrobeData

Wait_15ms Wait_15ms

bcf RS bcf RW movlw b'00111000' call StrobeData

Wait_15ms Wait_15ms

bcf RS bcf RW movlw b'00111000' call StrobeData

Wait_15ms Wait_15ms

call DisplayOFF_CursorOFF_BlinkOFF Wait_15ms Wait_15ms

call ClearDisplay Wait_15ms Wait_15ms

call EntryModeSet Wait_15ms Wait_15ms

call DisplayON_CursorON_BlinkON Wait_15ms Wait_15ms

movlw b'01001000' ;H call SendChar movlw b'01100101' ;e call SendChar movlw b'01101100' ;l call SendChar movlw b'01101100' ;l call SendChar movlw b'01101111' ;o call SendChar movlw b'01010111' ;W call SendChar movlw b'01101111' ;o call SendChar movlw b'01110010' ;r call SendChar movlw b'01101100' ;l call SendChar movlw b'01100100' ;d call SendChar

Eternal bsf PORTB, 0 nop bcf PORTB, 0 goto Eternal ;----------- StrobeData nop bsf ENABLE nop nop movwf DATA_PORT nop nop bcf ENABLE return ;----------- EntryModeSet CheckBusyFlag bcf RW movlw b'00000110' call StrobeData return ;----------- SendChar CheckBusyFlag bsf RS bcf RW call StrobeData return ;----------- ClearDisplay CheckBusyFlag bcf RW movlw 0x01 call StrobeData return ;----------- HomeCursor CheckBusyFlag bcf RW movlw 0x02 call StrobeData return ;----------- DisplayOFF_CursorOFF_BlinkOFF CheckBusyFlag bcf RW movlw b'00001000' call StrobeData return ;----------- DisplayOFF_CursorOFF_BlinkON CheckBusyFlag bcf RW movlw b'00001001' call StrobeData return ;----------- DisplayOFF_CursorON_BlinkOFF CheckBusyFlag bcf RW movlw b'00001010' call StrobeData return ;----------- DisplayOFF_CursorON_BlinkON CheckBusyFlag bcf RW movlw b'00001011' call StrobeData return ;----------- DisplayON_CursorOFF_BlinkOFF CheckBusyFlag bcf RW movlw b'00001100' call StrobeData return ;----------- DisplayON_CursorOFF_BlinkON CheckBusyFlag bcf RW movlw b'00001101' call StrobeData return ;----------- DisplayON_CursorON_BlinkOFF CheckBusyFlag bcf RW movlw b'00001110' call StrobeData return ;----------- DisplayON_CursorON_BlinkON CheckBusyFlag bcf RW movlw b'00001111' call StrobeData return ;----------- ShiftCursorRight CheckBusyFlag bcf RW movlw b'00010100' call StrobeData return ;----------- ShiftCursorLeft CheckBusyFlag bcf RW movlw b'00010000' call StrobeData return ;----------- ShiftDisplayRight CheckBusyFlag bcf RW movlw b'00011100' call StrobeData return ;----------- ShiftDisplayLeft CheckBusyFlag bcf RW movlw b'00011000' call StrobeData return ;----------- ;****************************************************************** Little_Delay Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall Stall return Big_Delay call Little_Delay call Little_Delay call Little_Delay call Little_Delay call Little_Delay call Little_Delay call Little_Delay call Little_Delay call Little_Delay call Little_Delay call Little_Delay call Little_Delay Medium_Delay call Little_Delay call Little_Delay call Little_Delay call Little_Delay call Little_Delay call Little_Delay call Little_Delay call Little_Delay call Little_Delay call Little_Delay call Little_Delay call Little_Delay call Little_Delay return ;----------- END

Reply to
Will

Hi, gone overboard with the delays:) I can't see the instruction that changes the port mode for the busy check, (this is not an 8051). remove the resistors (they are not helping). The strobe data doesnt need all those nops,( movwf port,bsf enable, 3 nops, bcf enable, return).

Reply to
CBarn24050

No comment on the hardware aspect of your design, but putting caps on data lines is unusual to say the least.

The main problem with getting Optrex LCDs to work is the initialization. The info provided by Optrex is only approximately accurate with respect to the time delays. I've had to insert looooong delays at each initialization step and then shorten them until failure, thus finding that some had to be substantially longer than Optrex says.

There's also a gotcha with the BUSY flag -- it doesn't start working at the point in the initialization process that Optrex states. A wait loop has to be used at each step until the end of initialization. The BUSY flag can and should be used from there onward.

Reply to
Everett M. Greene

I had exactly the same experience - took many frustrating hours to figure out and Optrex was zero help.

Yup

Reply to
Bob Stephens

I seem to remember that you were saying the Busy flag was connected to bit 6 Port B. Odd, because the busy flag is the highest data bit (bit 7) if I remember this right. Can you check your busy flag definition against the data sheet of the LCD chip? Have you got the data sheet of the HD44780, which is the prototypical chip everyone emulates?

I consider it advisable to change the order of the bcf and btfsc instructions, because the former disables the output of the data that you are reading with the second.

--
Cheers
Stefan
Reply to
Stefan Heinzmann

Make sure you give the LCD time to power up. I just hooked up a Optrex 2x16 display to a TI MSP430 and I had to put in huge delays before I ever started initializing the LCD. After I did that all of my problems went away....

--
Greg Deuerling
Fermi National Accelerator Laboratory
 Click to see the full signature
Reply to
Egads

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.