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


Comments: