; *****************************************
; * LCD-base routines for 4-Bit-interface *
; * of a 2-line LCD display to an ATMEL-  *
; * Port, Bits 4..7=Data, Bit 1=RS, Bit0=E*
; * Version 1, February 2002, (C) 2002 by *
; * Gerhard Schmidt, bug reports and sug- *
; * gestions to info@avr-asm-tutorial.net *
; *****************************************
;
; Hardware: LCD-Display on the active port
;
; Definitions, that must be defined in the calling
; program:
; - Stack operations must be initialised
; - Register rmp (R16..R31)
; - Clock frequency ftakt
; - pLcdPort Active LCD-Port
; - pLcdDdr Data direction registerof the active port
; Subroutines:
; - Lcd4Init: Initialise the LCD
; - Lcd4Chr: Display the character in rmp on the LCD
; - Lcd4PBcd: Display the packed BCD in rmp on the LCD
; - Lcd4ZTxt: Display the null-terminated string on the LCD
; - Lcd4RTxt: Display rmp chars from SRAM, starting at Z
;
; Definition for the LCD-port
.EQU cLcdWrite=0b11111111 ; Data direction write the LCD
.EQU cLcdDummy=0b00111000 ; Dummy-Function-Word
.EQU mLcdRs=0b00000010 ; RS-Bit Mask
.EQU bLcdEn=0 ; Enable Bit
.EQU c1s=200 ; Wait at start-up time (200 * 5 ms)
.EQU c5ms=ftakt/800 ; 5 ms Wait after each control word
.EQU c50us=ftakt/80000 ; 50 us Wait after each char
;
; Macro for Enable active time
;
; Version for 10 Mcs clock
;.MACRO enactive
;	nop
;	nop
;	nop
;	nop
;	nop
;.ENDMACRO
;
; Version für 4 Mcs clock
;
.MACRO enactive
	nop
	nop
.ENDMACRO
;
Lcd4Init:
	rcall LcdDelay1s ; Wait a second for the LCD
	ldi rmp,cLcdWrite ; Data direction to output
	out pLcdDdr,rmp
	ldi rmp,cLcdDummy ; Dummy to catch LCD
	rcall Lcd4Set ; send three times with 5 ms delay
	rcall LcdDelay5ms
	ldi rmp,cLcdDummy
	rcall Lcd4Set
	rcall LcdDelay5ms
	ldi rmp,cLcdDummy
	rcall Lcd4Set
	rcall LcdDelay5ms
	ldi rmp,0b00101000 ; Function Set to 4 Bit
	rcall Lcd4Ctrl ; output on the Control Port LCD
	ldi rmp,0b00010100 ; Cursor display shift
	rcall Lcd4Ctrl
	ldi rmp,0b00001100 ; LCD on
	rcall Lcd4Ctrl
	ldi rmp,0b00000110 ; Entry mode
	rcall Lcd4Ctrl
Lcd4Clear:
	ldi rmp,0b00000001 ; Set Lcd Clear
	rcall Lcd4Ctrl
Lcd4Home:
	ldi rmp,0b00000010 ; Set LCD Home Position
;
; Output of rmp on the Control-Port of the LCD
;
Lcd4Ctrl:
	push rmp ; save byte
	andi rmp,0xF0 ; clear lower nibble
	rcall Lcd4Set ; output upper nibble
	pop rmp ; restore byte
	swap rmp ; swap lower and upper nibble
	andi rmp,0xF0 ; clear lower nibble
	rcall Lcd4Set ; output lower nibble
	rjmp LcdDelay5ms ; done.
;
; Display the packed BCD in rmp on the LCD
;
Lcd4PBcd:
	push rmp ; Save on stack
	swap rmp ; Higher to lower nibble
	rcall Lcd4PBcd1 ; Output nibble
	pop rmp ; Restore from stack
Lcd4PBcd1:
	andi rmp,0x0F ; Mask upper nibble
	ori rmp,0x30 ; Nibble to ASCII
;
; Display char in rmp on the LCD
;
Lcd4Chr:
	push rmp ; save char on stack
	andi rmp,0xF0 ; clear lower nibble
	sbr rmp,mLcdRs ; Set RS-Bit
	rcall Lcd4Set ; output nibble
	pop rmp ; get char from stack
	swap rmp ; swap nibbles
	andi rmp,0xF0 ; clear lower nibble
	sbr rmp,mLcdRs ; Set RS-Bit
	rcall Lcd4Set ; output nibble
	rjmp LcdDelay50us ; ready
;
; Send nibble in rmp to LCD
;
Lcd4Set:
	out pLcdPort,rmp ; Byte to output port
	nop
	sbi pLcdPort,bLcdEn ; Set Enable-Bit
	enactive ; Delay macro
	cbi pLcdPort,bLcdEn ; Clear Enable Bit
	nop
	ret
;
; Delay by 1 second on start-up
;
LcdDelay1s:
	ldi rmp,c1s ; 200 * 5 ms wait
LcdDelay1s1:
	rcall LcdDelay5ms
	dec rmp
	brne LcdDelay1s1
	ret
;
; Delay by 5 ms following each Control Word
;
LcdDelay5ms:
	push ZH
	push ZL
	ldi ZH,HIGH(c5ms)
	ldi ZL,LOW(c5ms)
LcdDelay5ms1:
	sbiw ZL,1
	brne LcdDelay5ms1
	pop ZL
	pop ZH
	ret
;
; Delay by 50 Microseconds after each Char
;
LcdDelay50us:
	ldi rmp,c50us
LcdDelay50us1:
	nop
	dec rmp
	brne LcdDelay50us1
	ret
;
; Display at the position in rmp the string starting at Z (null-term.)
;
Lcd4ZTxt:
	sbr rmp,0b10000000 ; Set DD-RAM-Adress
	rcall Lcd4Ctrl
Lcd4ZTxt1:
	lpm ; Get a char
	tst R0 ; Null-Char?
	breq Lcd4ZTxtR
	mov rmp,R0
	rcall Lcd4Chr ; display the cahr in rmp
	adiw ZL,1 ; next char
	rjmp Lcd4ZTxt1 ; do it again
Lcd4ZTxtR:
	ret
;
; Display rmp chars from SRAM starting at Z on the LCD
;
Lcd4RTxt:
	mov R0,rmp ; R0 is counter
Lcd4RTxt1:
	ld rmp,Z+ ; read char
	rcall Lcd4Chr
	dec R0
	brne Lcd4RTxt1
	ret
