;;                 LCD-Routinen                ;;
;;                 ============                ;;
;;                            				   ;;
;;		Es muss im Programm  Register   	   ;;
;;      mit dem Namen tmp und tmp2 geben	   ;;
;;		Ausserdem müssen ZPH, ZPL und		   ;;
;;		YPH und YPL vorhanden sein			   ;;
;;		ausserdem muss am ende noch			   ;;
;;		"lcd_routines_advanced_dseg.asm"	   ;;
;;		eingebunden werden					   ;;									   ;;
;;											   ;;
;; 4bit-Interface                              ;;
;; DB4-DB7:       PC0-PC3                      ;;
;; RS:            PC4                          ;;
;; E:             PC5						   ;;
;; RW:			  PC6                          ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

		.CSEG

.equ PORT_LCD = PORTC
.equ DDR_LCD = DDRC
.equ PIN_RW = 6
.equ PIN_E = 5
.equ PIN_RS = 4
.equ PIN_B = 3
.equ lcd_buffer_size = 128


/* schreibt daten an das lcd in den buffer
   ! nur im 4-Bit Modus verwenden ! */
lcd_data:
		push	tmp

		push	tmp
		swap	tmp
		andi	tmp, 0b00001111
		sbr		tmp, 1<<PIN_RS
		rcall	lcd_buffer_in
		pop		tmp
		andi	tmp, 0b00001111
		sbr		tmp, 1<<PIN_RS
		rcall	lcd_buffer_in

		pop		tmp
		ret


/* schreibt befehle an das lcd in den buffer
   ! nur im 4-Bit Modus verwenden ! */
lcd_command:
		push	tmp

		push	tmp
		swap	tmp
		andi	tmp, 0b00001111
		rcall	lcd_buffer_in
		pop		tmp
		andi	tmp, 0b00001111
		rcall	lcd_buffer_in

		pop		tmp
		ret


/* Schreibt in den Buffer */
lcd_buffer_in:
		
		push	YL
		push	YH
		push	ZL
		push	ZH

		lds     ZL, lcd_pWrite
		lds     ZH, lcd_pWrite+1
		lds     YL, lcd_pRead
		lds     YH, lcd_pRead+1
 		
		cpi		ZL, ( LOW(lcd_buffer) + lcd_buffer_size )
		brne	lcd_buffer_write
		ldi		ZL, LOW(lcd_buffer)
		ldi		ZH, HIGH(lcd_buffer)
lcd_buffer_write:
		st		Z+, tmp
		
		sts		lcd_pWrite, ZL
		sts		lcd_pWrite+1, ZH

		pop		ZH
		pop		ZL
		pop		YH
		pop		YL

		ret

		
/* Holt daten und befehle aus dem Buffer
   und schreibt sie ins LCD */
lcd_buffer_out:

		push	YL
		push	YH
		push	ZL
		push	ZH
		push	tmp
		
		lds     ZL, lcd_pWrite
		lds     ZH, lcd_pWrite+1
		lds     YL, lcd_pRead
		lds     YH, lcd_pRead+1


		cp		ZL, YL
		breq	lcd_buffer_stop
		cpi		YH, High(lcd_buffer)
		brne	lcd_buffer_double_read
		cpi		YL, ( LOW(lcd_buffer) + lcd_buffer_size )
		brne	lcd_buffer_double_read
		ldi		YL, LOW(lcd_buffer)
		ldi		YH, HIGH(lcd_buffer)
lcd_buffer_double_read:
		ld		tmp, Y+
		out		PORT_LCD, tmp
		rcall	lcd_enable
		ld		tmp, Y+
		out		PORT_LCD, tmp
		rcall	lcd_enable
lcd_buffer_stop:

		
		sts		lcd_pRead, YL
		sts		lcd_pRead+1, YH
		
		pop		tmp
		pop		ZH
		pop		ZL
		pop		YH
		pop		YL

		ret


/* Enable-Puls-> Display holt die daten */
lcd_enable:
		sbi		PORT_LCD, PIN_E
		nop
		nop
		nop
		cbi		PORT_LCD, PIN_E
		ret


/* längere Pause für manche Befehle */
delay_5ms:
		push	tmp							;	tmp speichern
		
		ldi		tmp, (( XTAL / 40200 ) +2 ) ;	Wert für big_loop
delay_5_ms_big_loop:						;	big_loop
		push	tmp							;	big_loop
								
		ldi		tmp, 0x40					;	Wert für small_loop
delay_5_ms_small_loop:						;	small_loop
		dec		tmp							;	small_loop
		brne	delay_5_ms_small_loop		;	small_loop
		
		pop		tmp							;	big_loop
		dec		tmp							;	big_loop
		brne	delay_5_ms_big_loop			;	big_loop
		
		pop		tmp
		ret
		

/* initialisierung für 4-Bit Modus
   diese initialisierung sollte im
   Reset durchgeführt werden,
   da er eine gewisse Zeit dauert */
lcd_init:
		
		ldi		tmp, 0xff					;	Zunächst wird geschrieben
		out		DDR_LCD, tmp				;	-> Alle Pins auf AUSGANG
		
		ldi		tmp, 0x06					;	Nach anlegen der Versorgungs-
lcd_powerupwait:								;	spannung geben wir dem
		rcall	delay_5ms					;	Controller erstmal zeit für
		dec		tmp							;	seine eigene initialisierung
		brne	lcd_powerupwait					;	( ca 30 ms reichen dicke^^)
		
		ldi		tmp, 0x03					;	Nun müssen wir 3x 0x03 ins
		out		PORT_LCD, tmp				;	Steuerregister ( RS = 0 )
		rcall	lcd_enable					;	des lcds schreiben
		rcall	delay_5ms					;	mit je 5ms pause
		rcall	lcd_enable					;	...
		rcall	delay_5ms					;	...
		rcall	lcd_enable					;	...
		rcall	delay_5ms					;	...

		ldi		tmp, 0x02					;	jetzt noch eine 2 ins
		out		PORT_LCD, tmp				;	Seteuerregister und schon
		rcall	lcd_enable					;	sind wir im 4-Bit Modus
		rcall	delay_5ms					;	...
		ldi		tmp, 0b00101000
		rcall	lcd_command
		ldi		tmp, 0b00001100
		rcall	lcd_command
		ldi		tmp, 0b00000100
		rcall	lcd_command
		rcall	lcd_buffer_out
		
		
		ret
		

 ; Sendet den Befehl zur Löschung des Displays
lcd_clear:
		push 	tmp
        ldi   	tmp, 0b00000001      ; Display löschen
        rcall 	lcd_command
		pop		tmp
        ret
 
 ; Sendet den Befehl: Cursor Home
lcd_home:
		push	tmp
        ldi  	tmp, 0b00000010      ; Cursor Home
        rcall 	lcd_command
        pop		tmp
		ret

 ; Gibt ein Register Dzimal aus
lcd_data_dezimal:
		push	tmp
		push	tmp2
		
		mov		tmp2, tmp
		ldi		tmp, '0'-1
lcd_data_dezimal_h:
		inc		tmp
		subi	tmp2, 100
		brcc	lcd_data_dezimal_h
		subi	tmp2, -100
		rcall	lcd_data

		ldi		tmp, '0'-1
lcd_data_dezimal_z:
		inc		tmp
		subi	tmp2, 10
		brcc	lcd_data_dezimal_z
		subi	tmp2, -10
		rcall	lcd_data

		ldi		tmp, '0'
		add		tmp, tmp2
		rcall	lcd_data

		pop		tmp2
		pop		tmp
		ret


		.DSEG

		lcd_buffer:		.Byte lcd_buffer_size

		lcd_pWrite:		.Byte 2
		lcd_pRead:		.Byte 2
