.include "2313def.inc"

;**********************************************
;* Equates                                    *
;**********************************************

.equ	clock		= 4000000		;4 MHZ clock frequency 

.equ	STACKTOP	= RAMEND - 100

;**********************************************
;* The following delay constants are based on * 
;* an 4 MHZ clock (CLK)                       *
;* Times are not exact.                       *
;**********************************************

.equ	d15ms	= $c6			;15ms CLK/1024
.equ	d4x1ms	= $f0			;4.1ms CLK/1024
.equ	d1ms	= $c2			;1ms CLK/64
.equ	d500us	= $e1			;500us CLK/64
.equ	d100us	= $fa			;100us CLK/64
.equ	d40us	= $fe			;40us CLK/64


.equ	TSTOP	=0			;Stop Timer/Counter
.equ	TCK1	=1			;Timer/Counter runs from CK
.equ	TCK8	=2			;Timer/Counter runs from CK / 8
.equ	TCK64	=3			;Timer/Counter runs from CK / 64
.equ	TCK256	=4			;Timer/Counter runs from CK / 256
.equ	TCK1024	=5			;Timer/Counter runs from CK / 1024
.equ	TEXF	=6			;Timer/Counter runs from external falling edge
.equ	TEXR	=7			;Timer/Counter runs from external rising edge

.equ	LCDE	=0			;PORTB bit used for the LCD E signal
.equ	LCDDat	=1			;PORTB bit used for the LCD serial data
.equ	LCDClk	=2			;PORTB bit used for the LCD serial data clock


;**********************************************
;* Registers used                             *
;**********************************************

.def	SaveSREG    	= r15		;used in Delay

.def	A		= r16		;working reg, like the 68HC11 A register
.def	B		= r17		;working reg, like the 68HC11 B register
.def	DelayVal	= r18
.def	ClkDiv		= r19


.cseg
.org	$000				;Reset Vector
	rjmp	Reset
   

 ;Interrupt vectors

.org	INT0addr			;External Interrupt0 Vector
	reti
.org	INT1addr			;External Interrupt1 Vector
	reti
.org	ICP1addr			;Input Capture1 Interrupt Vector
 	reti
.org	OC1addr				;Output Compare1 Interrupt Vector Address
	reti
.org	OVF1addr			;Overflow1 Interrupt Vector
	reti
.org	OVF0addr			;Overflow0 Interrupt Vector
	rjmp	Tim0int
.org	URXCaddr			;UART Receive Complete Interrupt Vector
	reti
.org	UDREaddr			;UART Data Register Empty Interrupt Vector
	reti
.org	UTXCaddr			;UART Transmit Complete Interrupt Vector
	reti
.org	ACIaddr				;Analog Comparator Interrupt Vector
	reti
    

Reset:
	ldi    A, low(STACKTOP)
	out    SPL, A			;set low byte for stack pointer
	rcall  Setup			;set up timer, LCD port bits and LCD
RPLoop:
	rcall	ClearLCD
	ldi	A, 'Z'
	rcall	LCDChr
	ldi	A, 41
	rcall	CurPos
	ldi	A, 'Y'
	rcall	LCDChr

	ldi	A, 3
	rcall	CurPos
	ldi	A, 'M'
	rcall	LCDChr
	ldi	A, 'H'
	rcall	LCDChr
	ldi	A, 'z'
	rcall	LCDChr
	ldi	A, $7e
	rcall	LCDChr

rtr:
		rjmp	rtr
		rjmp	RPLoop 		;wait here until something interesting happens
;**********************************************
;* ClearLCD								   	
;**********************************************
ClearLCD:
	ldi	A, $01			;RS DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
	rcall	LCDcmd			;0   0   0   0   0   0   0   0   1
					;Clear screen, cursor home
 	ldi	DelayVal, d1ms 
	rcall	Delay 
	rcall	Delay 
	ret
CurPos:
	ori	A, $80
	rcall	LCDCmd
 	ldi	DelayVal, d1ms 
	rcall	Delay
	ret 

;********************************************** 
;* Setup                                      *
;* Initialize the timer, LCD port and LCD     *
;**********************************************
Setup:               

;** Timer setup **
	ldi	ClkDiv, TCK64
	ldi	A, TSTOP		;Timer 0 off (just in case)
	out	TCCR0, A		;Stop timer
	ldi	A, 0b00000010		;Enable Timer 0 interrupt
	out	TIMSK, A
	sei				;enable interrupts

;** LCD port setup and HD44780 LCD setup **
	sbi	DDRB, LCDE		;DDRB bit 5 = 1 = output
	sbi	DDRB, LCDDat		;DDRB bit 6 = 1 = output
	sbi	DDRB, LCDClk		;DDRB bit 7 = 1 = output
	cbi	PORTB, LCDE		;set E low
	cbi	PORTB, LCDDat		;set Data bit low
	cbi	PORTB, LCDClk		;set Clk low
	 
	ldi	ClkDiv, TCK1024		;switch to a 1024 clock divisor
	ldi	DelayVal, d15ms  	;15ms delay
	rcall	Delay

	ldi	A, $30
	rcall	LCDCmd

	ldi	DelayVal, d4x1ms	;4.1ms countdown
	rcall	Delay

	ldi	A, $30
	rcall	LCDCmd

	ldi	ClkDiv, TCK64		;switch to a 64 clock divisor
	ldi	DelayVal, d100us 
	rcall	Delay 

	ldi	A, $30
	rcall	LCDCmd


	ldi	ClkDiv, TCK1024		;switch to a 1024 clock divisor
	ldi	DelayVal, d4x1ms 
	rcall	Delay

	ldi	A, $38			;RS DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
	rcall	LCDCmd			;0   0   0   1   1   1   0   x   x
					;8-bit operation, 1/16 duty cycle
					;5x8 dot matrix

	ldi	ClkDiv, TCK64		;switch to a 64 clock divisor
	ldi	DelayVal, d40us 
	rcall	Delay 

	ldi	A, $08			;RS DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
	rcall	LCDCmd			;0   0   0   0   0   1   0   0   0
					;Display off, cursor off, blink off
	ldi	DelayVal, d40us 
	rcall	Delay 

	ldi	A, $01			;RS DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
	rcall	LCDcmd			;0   0   0   0   0   0   0   0   1
					;Clear screen, cursor home
	ldi	DelayVal, d1ms 
	rcall	Delay 
	rcall	Delay 

	ldi	A, $06			;RS DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
	rcall	LCDCmd			;0   0   0   0   0   0   1   1   0
					;Increment cursor to the right when writing, don't shift screen
	ldi	DelayVal, d40us 
	rcall	Delay 

	ldi	A, $0c			;RS DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
	rcall	LCDCmd          	;0   0   0   0   0   0   1   1   0
					;Display on, cursor off, blink off
	ldi	DelayVal, d40us 
	rcall	Delay 

	ret
		     
;**********************************************
;* Write byte to LCD bus                      *
;**********************************************

;**********************************************
;* PutByte clock byte into 74hc164.           *
;* Data is in AReg                            *
;* BReg is used as acounter                   *
;**********************************************
PutByte:
	ldi	B, 8			;bit counter
ShiftB:
	cbi	PORTB, LCDDat		;set LCD Data bit to 0
	lsl	A			;shift bits in AReg into carry
	brcc	CLKBit			;if zero, clock it out
	sbi	PORTB, LCDDat		;if 1, set LCD Data bit to 1
CLKBit: 
	sbi	PORTB, LCDClk		;bit clocks on rising edge
	cbi	PORTB, LCDClk		;bring clock back to 0
NextB:
	dec	B			;shift out 8 bits
	brne	ShiftB
	ret

;**********************************************
;* LCDCmd - Send a command to the LCD         *
;* data in AReg                               *
;**********************************************
LCDCmd: 
	rcall	PutByte
	cbi	PORTB, LCDDat		;set RS low
	sbi	PORTB, LCDE		;set E High
	cbi	PORTB, LCDE		;set E low
	ret

;**********************************************
;* LCDChr - Display a character on the LCD    *
;* data in AReg                               *
;**********************************************
LCDChr: 
	rcall	PutByte
	sbi	PORTB, LCDDat		;set RS High
	sbi	PORTB, LCDE		;set E High
	cbi	PORTB, LCDE		;set E low
	ldi	DelayVal, d1ms 
	rcall	Delay
	ret

;**********************************************
;* Misc timing routines                       *
;**********************************************

;**********************************************
;* Timer0 overflow interrupt handler          *
;**********************************************
Tim0int:
	cli				;disable interrupts
	push	A
	set				;Set T flag
	ldi	A, TSTOP		;Stop Timer 0
	out	TCCR0, A
	pop	A
	sei				;re-enable interrupts
	reti                    

;**********************************************
;* Delay   time in us based on CLK value      *
;* DelayVal holds the delay value.            *
;* ClkDiv has the prescaler value             *
;**********************************************
Delay:
	in	SaveSREG, SREG		;Save status register
	out	TCNT0, DelayVal
	clt				;Clear T
	out	TCCR0, ClkDiv		;Load prescaler and run timer
Dwait:  
	brtc	Dwait			;Wait for timer 0 interrupt to set T
	out	SREG, SaveSREG
	ret

       

