
#define x16F688

#ifdef x16F688
#include <p16F688.inc>
     __config (_INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _IESO_OFF & _FCMEN_OFF)
#endif


SPS_DELAY_UNIT	equ	0x10
SPS_DELAY_HALF	equ	0x08

SER_OUT			equ	PORTC
SER_OUT_BIT		equ	3
LCD_DEVICE_ID	equ	b'00000010'

	cblock 0x20
	SER_TMP
	LOOKUP_TMP
	TEXT_LOOP_CNT
	DELAY_HH
	DELAY_H
	DELAY_L
	; SPS Send
	DAT_H
	DAT_L
	SEND_BIT_COUNTER
	DELAY_COUNTER
	; PAR
	PAR
	PAR_TMP
	PAR_BIT_COUNTER
	; Test
	TEST_COUNTER
	endc

#include LCDdefs.inc

Main
	call	Init_PORTS
	call	SPS_Send_Init
	movlw	0x02
	call	BigDelay
	clrf	TEST_COUNTER
TextLoop
	clrf	TEXT_LOOP_CNT
	movlw	LCDCMD_CLEAR
	call	SPS_Send_CMD
	call	LetterDelay
	movlw	0x00
	addwf	TEST_COUNTER,w
	iorlw	LCDCMD_SET_DD_RAM
	call	SPS_Send_CMD
	call	LetterDelay
SendLetter
	movf	TEXT_LOOP_CNT,w
	call	TableLookup
	addlw	0x00
	btfsc	STATUS,Z
	goto	GoToLine2
	call	SPS_Send_DAT
	call	LetterDelay
	incf	TEXT_LOOP_CNT,f
	movlw	0x0C	; # of letters to display
	subwf	TEXT_LOOP_CNT,w
	btfss	STATUS,Z
	goto	SendLetter
	movlw	0x03
	call	BigDelay
	incf	TEST_COUNTER,f
	movf	TEST_COUNTER,w
	sublw	0x0A
	btfsc	STATUS,Z
	clrf	TEST_COUNTER
	goto	TextLoop

GoToLine2
	movf	TEST_COUNTER,w
	iorlw	LCDCMD_SET_DD_RAM | 0x40
	call	SPS_Send_CMD
	call	LetterDelay
	incf	TEXT_LOOP_CNT,f	
	goto	SendLetter

BigDelay
	movwf	DELAY_HH
BigDelay_0
	movlw	0xFF
	movwf	DELAY_H
	movlw	0xFF
	movwf	DELAY_L
	call	Delay
	decf	DELAY_HH,f
	btfss	STATUS,Z
	goto	BigDelay_0
	return

LetterDelay
	movlw	0x08
	movwf	DELAY_H
	movlw	0xFF
	movwf	DELAY_L
	goto	Delay

Delay
	nop
	nop
	nop
	nop	
	decf	DELAY_L,f
	btfss	STATUS,Z
	goto	Delay
	decf	DELAY_H,f
	btfss	STATUS,Z
	goto	Delay
	return

Init_PORTS
	banksel	PORTC
	clrf	PORTC	;Lower all PORTC outputs
	banksel	ANSEL
	movlw	b'00000000'
	movwf	ANSEL	;All digital
	banksel	TRISC
	movlw	b'11111111'
	movwf	TRISC	;Port C - all input
	bcf		TRISC,SER_OUT_BIT
	banksel	PORTC
	return

SPS_Send_Init
	bcf		SER_OUT,SER_OUT_BIT
	return

SPS_Send_CMD
	movwf	DAT_L
	movlw	0x01
	iorlw	LCD_DEVICE_ID
	movwf	DAT_H
	goto	SPS_Send
SPS_Send_DAT
	movwf	DAT_L
	movlw	0x00
	iorlw	LCD_DEVICE_ID
	movwf	DAT_H
SPS_Send
	call	Stamp_PAR
	call	SPS_Pulse
	call	SPS_SendDelay_UNIT
	call	SPS_Pulse
	movlw	0x08
	movwf	SEND_BIT_COUNTER
SPS_Send_0			; Send DAT_H bits
	call	SPS_SendDelay_HALF
	btfsc	DAT_H,7
	call	SPS_SendDelay_UNIT
	call	SPS_Pulse
	rlf		DAT_H,f	
	decf	SEND_BIT_COUNTER,f
	btfss	STATUS,Z
	goto	SPS_Send_0
	movlw	0x08
	movwf	SEND_BIT_COUNTER
SPS_Send_1			; Send DAT_L bits
	call	SPS_SendDelay_HALF
	btfsc	DAT_L,7
	call	SPS_SendDelay_UNIT
	call	SPS_Pulse
	rlf		DAT_L,f	
	decf	SEND_BIT_COUNTER,f
	btfss	STATUS,Z
	goto	SPS_Send_1
	return

SPS_Pulse	; 1 uS ?  This is way more but less can be missed by receiver
	bsf		SER_OUT,SER_OUT_BIT
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	bcf		SER_OUT,SER_OUT_BIT
	return

SPS_SendDelay_HALF
	movlw	SPS_DELAY_HALF
	goto	WDelay

SPS_SendDelay_UNIT
	movlw	SPS_DELAY_UNIT
	goto	WDelay

WDelay
	movwf	DELAY_COUNTER
WDelay_0
	nop
	nop
	nop
	nop
	decf	DELAY_COUNTER,f
	btfss	STATUS,Z
	goto	WDelay_0
	return

Stamp_PAR
	call	Generate_PAR
	rlf		DAT_H,f
	rlf		DAT_H,f
	rrf		PAR,f
	rrf		DAT_H,f
	rrf		PAR,f
	rrf		DAT_H,f
	return

Generate_PAR
	clrf	PAR
	movlw	b'11000000'
	iorwf	DAT_H,w
	call	PAR_Byte
	movf	DAT_L,w
	call	PAR_Byte
	return

PAR_Byte
	movwf	PAR_TMP
	movlw	0x04
	movwf	PAR_BIT_COUNTER
PAR_Byte_0
	rlf		PAR_TMP,f
	btfss	STATUS,C
	goto	PAR_Byte_1
	movlw	b'00000010'
	xorwf	PAR,f
PAR_Byte_1
	rlf		PAR_TMP,f
	btfss	STATUS,C
	goto	PAR_Byte_2
	movlw	b'00000001'
	xorwf	PAR,f
PAR_Byte_2
	decf	PAR_BIT_COUNTER,f
	btfss	STATUS,Z
	goto	PAR_Byte_0
	return


	        org 0x101
TableLookup
	movwf	LOOKUP_TMP
	movlw	0x01
	movwf	PCLATH
	movf	LOOKUP_TMP,w
	addwf	PCL,f
	retlw	LCD_H
	retlw	LCD_e
	retlw	LCD_l
	retlw	LCD_l
	retlw	LCD_o
	retlw	0x00
	retlw	LCD_W
	retlw	LCD_o
	retlw	LCD_r
	retlw	LCD_l
	retlw	LCD_d
	retlw	LCD_EXCLAMATION_POINT
	retlw	LCD_SPACE
	retlw	LCD_SPACE
	END
