; ; LCD module commands and utilities ; ;********************************************************************* DisLCD ; disable lcd module output ;********************************************************************* ; install this command in the CmdMenu lookup table CmdPC = $ ; save current inline assembly PC value org CurCmdMenuAdr ; set assembly PC to addr for new entry ; CmdMenu table entry data "LCDOFF\r", CmdPC, "Disable LCD output\r\n" CurCmdMenuAdr = $ ; set current CmdMenu addr for next entry org CmdPC ; begin cmd code gen at inline address bcf lcdFlags, LCDPrsnt ; clear lcd present flag goto DspLCD ; go display lcd status ; ;********************************************************************* EnLCD ; enable lcd module output ;********************************************************************* ; install this command in the CmdMenu lookup table CmdPC = $ ; save current inline assembly PC value org CurCmdMenuAdr ; set assembly PC to addr for new entry ; CmdMenu table entry data "LCDON\r", CmdPC, "Enable LCD output\r\n" CurCmdMenuAdr = $ ; set current CmdMenu addr for next entry org CmdPC ; begin cmd code gen at inline address call INIT_LCD ; initialize lcd module bsf lcdFlags, LCDPrsnt ; set lcd present flag ; fall through to display lcd status ; ;********************************************************************* DspLCD ; display lcd module status ;********************************************************************* ; install this command in the CmdMenu lookup table CmdPC = $ ; save current inline assembly PC value org CurCmdMenuAdr ; set assembly PC to addr for new entry ; CmdMenu table entry data "LCD\r", CmdPC, "Display LCD status\r\n" CurCmdMenuAdr = $ ; set current CmdMenu addr for next entry org CmdPC ; begin cmd code gen at inline address ; copy first part of output string into output buffer using FSR0 CpyTbl2Out LcdD btfsc lcdFlags, LCDPrsnt ; if lcd isn't present then skip goto LCDcont ; otherwise don't print NOT CpyTbl2Out NotD ; print NOT LCDcont CpyTbl2Out ActiveD ; complete output string return ; return from Cmd ; This is the end of the functions executable code ; ; These data statements store constant ascii output strings in program ; memory. They're accessed using the CpyTbl2Buf and CpyTblCont macros ; with the addresses given by the labels. LcdD ; constant string for lcd status display data "\nLCD module is ",0 NotD ; constant string for NOT display data "NOT ",0 ActiveD ; constant string for active display data "active\n",0 ; ; additional LCD routines ; InitLCD clrf lcdFlags ; initalize lcd flags return ; Cmd2LCD ; send cmd line to LCD btfss lcdFlags, LCDPrsnt ; skip if lcd present flag is set return ; otherwise return movlw 0x0D ; load CR char call SEND_CHAR ; send it to LCD movlw 0x0A ; load LF char call SEND_CHAR ; send it to LCD movlw '>' ; load prompt char call SEND_CHAR ; send it to LCD movfp rxPtr, FSR0 LineLCD incf FSR0 movfp INDF0, WREG call SEND_CHAR movlw 0x0D cpfseq INDF0 goto LineLCD return ; Out2LCD ; send output line to LCD btfss lcdFlags, LCDPrsnt ; skip if lcd present flag is set return ; otherwise return movfp txPtr, FSR0 OutLCD tstfsz INDF0 goto $+2 return movfp INDF0, WREG call SEND_CHAR incf FSR0 goto OutLCD ; ; LM032L lcd module initialization and interface routines and variables ; writteb in 17Cxx assembly. ; ; include this file after the cblock and org statement in the main file ; ; The interface is defined as 4 bit using D0-D3 of the port LCD defined ; below. The control signals are on the upper nibble of the same port. ; ; set the port used for the LCD interface here LCD EQU PORTC ; on the '756 demo board the LCD i/f is LCD_DDR EQU DDRC ; on PORTC LCD_BNK EQU 1 ; which is in bank 1 ; ; LCD Control Signal names. ; E EQU 6 ; LCD Enable control line RW EQU 5 ; LCD Read/Write control line RS EQU 4 ; LCD Register Select control line ; ; set the dewice frequency here Dev_Freq EQU D'16000000' ; Device Frequency is 4 MHz LCD_INIT_DELAY EQU (HIGH ((( Dev_Freq / 4 ) * D'46' / D'10000' ) / 3 ) ) + 1 ; ; LCD Module commands ; DISP_ON EQU 0x00C ; Display on DISP_ON_C EQU 0x00E ; Display on, Cursor on DISP_ON_B EQU 0x00F ; Display on, Cursor on, Blink cursor DISP_OFF EQU 0x008 ; Display off CLR_DISP EQU 0x001 ; Clear the Display ENTRY_INC EQU 0x006 ; ENTRY_INC_S EQU 0x007 ; ENTRY_DEC EQU 0x004 ; ENTRY_DEC_S EQU 0x005 ; DD_RAM_ADDR EQU 0x080 ; Least Significant 7-bit are for address DD_RAM_UL EQU 0x080 ; Upper Left coner of the Display CURS_LEFT EQU 0x10 ; shift cursor left CURS_RIGHT EQU 0x14 ; shift cursor right ; cblock ; variable declaration lcdFlags ; status flags for LCD module temp ; used by SEND_CHAR and SEND_CMD busyread ; used by BUSY_CHECK TEMP0 ; used for delay in INIT_LCD TEMP1 ; " " endc ; high active flags in lcdFlags LCDPrsnt equ 0 ; lcd module is present ; ; ;******************************************************************* ;* The LCD Module Subroutines * ;******************************************************************* ; ;******************************************************************* ;* SEND_CHAR - Sends character in W to LCD * ;* This routine splits the character into the upper and lower * ;* nibbles and sends them to the LCD, upper nibble first. * ;* The data is transmitted on the PORT<3:0> pins * ;* Affects: W and temp * ;******************************************************************* ; SEND_CHAR movlb LCD_BNK ; select SFR bank for LCD movwf temp ; save char to be sent call BUSY_CHECK ; wait for LCD ready ; movfp busyread, WREG ; DEBUG fetch last cursor position ; movwf PORTD ; DEBUG display on leds movlw 0x08 ; test for backspace cpfseq temp goto NOT_BACK ; if not keep going ; process backspace with wrap araound movfp busyread, WREG ; fetch cursor position bcf WREG, 6 ; clear row indicating bit tstfsz WREG ; skip if 0 to process wrap goto NOWRAP ; otherwise no wrap around movfp busyread, WREG ; fetch cursor position btg WREG, 6 ; toggle row iorlw D'19' ; set to last visible location bsf WREG, 7 ; set bit to create load addr cmd call SEND_CMD ; send to display movlw ' ' ; load space char to clear spot call SEND_CHAR ; recursively call to send movfp busyread, WREG ; fetch cursor position andlw 0x40 ; clear all but row indicating bit iorlw D'19' ; set to last visible location bsf WREG, 7 ; set bit to create load addr cmd call SEND_CMD ; send to display return NOWRAP movlw CURS_LEFT ; load command to backup cursor call SEND_CMD ; send the determined cmd to the display movlw ' ' ; load space char to clear spot call SEND_CHAR ; recursively call to send movlw CURS_LEFT ; backup cursor again call SEND_CMD ; send to display return NOT_BACK movlw 0x0D ; test for carriage return cpfseq temp goto NOT_CR ; if not keep going ; process carriage return movfp busyread, WREG ; fetch current cursor position andlw 0x40 ; clear all but row indicating bit bsf WREG, 7 ; set bit to create load addr cmd call SEND_CMD return NOT_CR movlw 0x0A ; test for line feed cpfseq temp goto NOT_LF ; if not keep going ; process line feed and clear rest of line movfp busyread, WREG ; fetch current cursor position btg WREG, 6 ; toggle row movwf TEMP0 ; save it bsf WREG, 7 ; set bit to create load addr cmd call SEND_CMD ; toggle to other row on lcd movfp busyread, WREG ; fetch curson position bcf WREG, 6 ; clear row indicating bit movwf TEMP1 ; save it SPACES ; clear rest of new row movlw 18 ; test for 19 or greater cpfsgt TEMP1 ; if cursor is in view skip goto BACK_UP ; otherwise backup to original position movlw ' ' ; load a space call SEND_CHAR ; recursively call to send incf TEMP1 ; inc cursor position goto SPACES BACK_UP ; go back to original position movfp TEMP0, WREG ; fetch old position bsf WREG, 7 ; set bit to create load addr cmd call SEND_CMD return NOT_LF ; printable character swapf temp, W ; get upper nibble into lower andlw 0x0F ; mask out D4-D7, clear RW movwf LCD ; output upper data nibble bsf LCD, RS ; set RS to data nop ; allow RS -> E > 140nS @ 33MHz bsf LCD, E ; raise E nop ; nop ; nop ; bcf LCD, E ; lower E > 450nS @ 33MHz movfp temp, WREG ; get lower nibble andlw 0x0F ; mask out D4-D7, clear RW movwf LCD ; output lower data nibble bsf LCD, RS ; set RS to data nop ; allow RS -> E > 140nS @ 33MHz bsf LCD, E ; raise E nop ; nop ; nop ; bcf LCD, E ; lower E > 450nS @ 33MHz ; test for wrap around movfp busyread, WREG ; fetch last cursor position bcf WREG, 6 ; clear row indicating bit sublw D'18' ; test for 19 or greater btfsc ALUSTA, C ; if cursor is out of view skip return ; otherwise return ; process carriage return and line feed movfp busyread, WREG ; fetch current cursor position andlw 0x40 ; clear all but row indicating bit btg WREG, 6 ; toggle row bsf WREG, 7 ; set bit to create load addr cmd call SEND_CMD return ; ;******************************************************************* ;* SendCmd - Sends command in W to LCD * ;* This routine splits the command into the upper and lower * ;* nibbles and sends them to the LCD, upper nibble first. * ;* The data is transmitted on the PORT<3:0> pins * ;* Affects: W and temp * ;******************************************************************* ; SEND_CMD movwf temp ; save cmd to be sent movlb LCD_BNK ; select SFR bank for LCD call BUSY_CHECK ; wait for LCD ready swapf temp, W ; get upper nibble into lower andlw 0x0F ; mask out D4-D7, clear RW and RS movwf LCD ; output upper data nibble nop ; allow RS & RW -> E > 140nS @ 33MHz bsf LCD, E ; raise E nop ; nop ; nop ; bcf LCD, E ; lower E > 450nS @ 33MHz movfp temp, WREG ; get lower nibble andlw 0x0F ; mask out D4-D7, clear RW and RS movwf LCD ; output lower data nibble nop ; allow RS & RW -> E > 140nS @ 33MHz bsf LCD, E ; raise E nop ; nop ; nop ; bcf LCD, E ; lower E > 450nS @ 33MHz return ; ;******************************************************************* ;* This routine checks the busy flag, returns when not busy * ;* If a the routine checks for ;* Affects: W and read value returned in busyread * ;******************************************************************* ; BUSY_CHECK call SHORT_DELAY ; delay some movlw 0x0F ; set data pins to input iorwf LCD_DDR ; bcf LCD, RS ; clear for cmd mode bsf LCD, RW ; set for read nop ; allow RW -> E > 140nS @ 33MHz bsf LCD, E ; raise E nop ; allow data access > 320nS nop ; even at 33MHz swapf LCD, W ; read upper nibble into W bcf LCD, E ; lower E > 450nS @ 33MHz andlw 0xF0 ; set lower nibble to 0 movwf busyread ; save in busyread nop ; allow > 1uS E cycle @ 33MHz bsf LCD, E ; raise E nop ; allow data access > 320nS nop ; even at 33MHz movfp LCD, WREG ; read lower nibble bcf LCD, E ; lower E > 450nS @ 33MHz andlw 0x0F ; set upper nibble to 0 iorwf busyread, W ; merge nibbles btfsc WREG, 7 ; if busy don't skip goto BUSY_CHECK ; check again movwf busyread ; otherwise save read value in busyread movlw 0xF0 ; set LCD port pins to output andwf LCD_DDR ; return ; return with lcd present ; ; This routine takes the calculated times that the delay loop needs to ; be executed, based on the LCD_INIT_DELAY EQUate that includes the ; frequency of operation. ; LCD_DELAY MOVLW LCD_INIT_DELAY ; MOVWF TEMP0 ; CLRF TEMP1 ; LOOP2 DECFSZ TEMP1, F ; Delay time = MSD * ((3 * 256) + 3) * Tcy GOTO LOOP2 ; = 4.6mS - jea DECFSZ TEMP0, F ; GOTO LOOP2 ; return SHORT_DELAY clrf WREG ; init WREG decfsz WREG ; delay 3 * 256 * Tcy goto $-1 ; return ; ; Initilize the LCD Display Module after power up ; INIT_LCD ; ; Initialize port LCD to drive lcd module ; movlb LCD_BNK ; select SFR bank for LCD bcf LCD_DDR, E ; set E as an output bcf LCD_DDR, RW ; set RW as an output bcf LCD_DDR, RS ; set RS as an output movlw 0xF0 ; andwf LCD_DDR ; set low nibble as data output clrf LCD ; init all bits in LCD to 0 ; delay > 15ms call LCD_DELAY call LCD_DELAY call LCD_DELAY call LCD_DELAY movlw 0x03 ; Command for 8-bit interface movwf LCD ; clearing RS & RW nop ; allow RS & RW -> E > 140nS @ 33MHz bsf LCD, E ; raise E nop ; nop ; nop ; bcf LCD, E ; lower E > 450nS @ 33MHz ; delay > 4.1ms call LCD_DELAY movlw 0x03 ; Command for 8-bit interface movwf LCD ; clearing RS & RW nop ; allow RS & RW -> E > 140nS @ 33MHz bsf LCD, E ; raise E nop ; nop ; nop ; bcf LCD, E ; lower E > 450nS @ 33MHz ; delay > 100us call LCD_DELAY movlw 0x03 ; Command for 8-bit interface movwf LCD ; clearing RS & RW nop ; allow RS & RW -> E > 140nS @ 33MHz bsf LCD, E ; raise E nop ; nop ; nop ; bcf LCD, E ; lower E > 450nS @ 33MHz ; delay > 100us call LCD_DELAY movlw 0x02 ; Command for 4-bit interface movwf LCD ; clearing RS & RW nop ; allow RS & RW -> E > 140nS @ 33MHz bsf LCD, E ; raise E nop ; nop ; nop ; bcf LCD, E ; lower E > 450nS @ 33MHz ; ; Command sequence for 4-bit mode and 2 lines of 5x8 characters ; movlw 0x02 ; 4-bit mode movwf LCD ; output upper cmd nibble nop bsf LCD, E ; raise E nop ; nop ; nop ; bcf LCD, E ; lower E > 450nS @ 33MHz movlw 0x08 ; 2 line display movwf LCD ; output lower cmd nibble nop ; allow > 1uS E cycle @ 33MHz bsf LCD, E ; raise E nop ; nop ; nop ; bcf LCD, E ; lower E > 450nS @ 33MHz ; ; Busy Flag should be valid after this point ; MOVLW DISP_OFF ; Display Off CALL SEND_CMD ; Send This command to the Display Module MOVLW CLR_DISP ; Clear the Display CALL SEND_CMD ; Send This command to the Display Module MOVLW ENTRY_INC ; Set Entry Mode Inc., No shift CALL SEND_CMD ; Send This command to the Display Module MOVLW DISP_ON ; Display On, no Cursor CALL SEND_CMD ; Send This command to the Display Module movlw 0x0A ; load LF char call SEND_CHAR ; send it to LCD RETURN