;
; 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