;********************************************************************************
;*				*
;*	USART Routinen       		*
;*	TX_out            gibt r16 über TX aus		*
;*                 	RX_In             holt Byte vom Puffer nach r16	*
;*                                    Carry set = Byte vorhanden	*
;*				*
;********************************************************************************
.EQU	F_CPU	= 8000000
.EQU	BAUD	= 38400   ; Baudrate

.EQU	TX_Buffer_Size	= 64
.EQU	RX_Buffer_Size	= 2
;-------------------------------------------------------------------------------
.EQU	TX_Puffer_End	= low(TX_Puffer+TX_Buffer_Size)
.EQU	RX_Puffer_End	= low(RX_Puffer+RX_Buffer_Size) 
; Berechnungen
.equ UBRR_VAL   = ((F_CPU+BAUD*8)/(BAUD*16)-1)  ; clever runden
.equ BAUD_REAL  = (F_CPU/(16*(UBRR_VAL+1)))     ; Reale Baudrate
.equ BAUD_ERROR = ((BAUD_REAL*1000)/BAUD-1000)  ; Fehler in Promille
 
.if ((BAUD_ERROR>10) || (BAUD_ERROR<-10))       ; max. +/-10 Promille Fehler
  .error "Systematischer Fehler der Baudrate grösser 1 Prozent und damit zu hoch!"
.endif
;------------------- Uart Variabeln --------------------------------------------
.dseg
TX_Puffer:	.byte TX_Buffer_Size
RX_Puffer:	.byte RX_Buffer_Size
TX_Buffer_Level:	.byte 1
RX_Pointer_PRG:	.byte 1
RX_Pointer_IRQ:	.byte 1
TX_Pointer_PRG:	.byte 1
TX_Pointer_IRQ:	.byte 1
.cseg
;------------------ Initialisiert Uart -----------------------------------------
Uart_init:	ldi r16,0
	sts RX_Pointer_PRG,r16
	sts RX_Pointer_IRQ,r16
	sts TX_Pointer_PRG,r16
	sts TX_Pointer_IRQ,r16

	ldi r16,TX_Buffer_Size-1
	sts TX_Buffer_Level,r16	
	ldi r16,High(UBRR_VAL)
	out UBRRH,r16
	ldi r16,LOW(UBRR_VAL)
	out UBRRL,r16
	ldi r16,(1<<UCSZ1)|(1<<UCSZ0) 
	out UCSRC,r16
	ldi r16,(1<<RXCIE)|(1<<RXEN)|(1<<TXEN)
	out UCSRB,r16
	ret
;------------- RX Interruptroutine --------------------------
URXC0_:	push r0
	in   r0, SREG
	push r0
	push zl
	push zh
	push yl
	ldi zl,low(RX_Puffer+RX_Buffer_Size-1)
	ldi zh,high(RX_Puffer+RX_Buffer_Size-1)
	lds yl,RX_Pointer_IRQ
	sub zl,yl
	sbci zh,0
	in r0,UDR
	st z,r0
	inc yl
	cpi yl,RX_Buffer_Size
	brne no_RX_IRQ_Overrun 
	ldi yl,0
no_RX_IRQ_Overrun:	sts RX_Pointer_IRQ,yl
	pop yl
	pop zh
	pop zl
	pop r0
	out SREG, r0
	pop r0
	reti
;------------- Eingabe Uart ---------------------------------
;holt Byte vom U_Puffer nach xl -- Carry set = Byte vorhanden
RX_In:	push zl
	push zh
	push yl
	lds yl,RX_Pointer_PRG
	lds zh,RX_Pointer_IRQ
	cp yl,zh
	clc
	breq RX_Puffer_leer

	ldi zl,low(RX_Puffer+RX_Buffer_Size-1)
	ldi zh,high(RX_Puffer+RX_Buffer_Size-1)
	sub zl,yl
	sbci zh,0
	ld r16,z
	inc yl
	cpi yl,RX_Buffer_Size
	brne no_RX_Overrun 
	ldi yl,0
no_RX_Overrun:	sts RX_Pointer_PRG,yl
	sec
RX_Puffer_leer:	pop yl
	pop zh
	pop zl
	ret

;-------------TX Interrupt Routine -------------------------
UDRE0_:	push r0
	in   r0, SREG
	push r0
	push zl
	push zh
	push yl
	lds zh,TX_Pointer_PRG
	lds zl,TX_Pointer_IRQ
	cp zl,zh
	brne TX_ausgeben	;wenn Zeiger ungleich dann ausgeben
TX_raus:	cbi  UCSRB,UDRIE 	;sonst Interrupt sperren und raus	
	rjmp TX_IRQ_Ende

TX_ausgeben:	ldi zl,low(TX_Puffer+TX_Buffer_Size-1)
	ldi zh,high(TX_Puffer+TX_Buffer_Size-1)
	lds yl,TX_Pointer_IRQ
	sub zl,yl
	sbci zh,0
	ld r0,z
	out UDR,r0
	inc yl
	cpi yl,TX_Buffer_Size
	brne no_IRQ_TX_Overrun 
	ldi yl,0
no_IRQ_TX_Overrun:	sts TX_Pointer_IRQ,yl
	lds yl,TX_Buffer_Level
	inc yl
	sts TX_Buffer_Level,yl
TX_IRQ_Ende:	pop yl
	pop zh
	pop zl
	pop r0
	out SREG, r0
	pop r0
	reti
;--------------------------------------------------------------
TX_out:	push zl
	push zh
	push yl

TX_out_wait:	lds yl,TX_Buffer_Level
	tst yl
	breq TX_out_wait
	dec yl
	sts TX_Buffer_Level,yl

	ldi zl,low(TX_Puffer+TX_Buffer_Size-1)
	ldi zh,high(TX_Puffer+TX_Buffer_Size-1)
	lds yl,TX_Pointer_PRG
	sub zl,yl
	sbci zh,0
	st z,r16
	inc yl
	cpi yl,TX_Buffer_Size
	brne no_TX_Overrun 
	ldi yl,0
no_TX_Overrun:	sts TX_Pointer_PRG,yl

	sbi UCSRB,UDRIE ;Interrupt freigeben
	pop yl
	pop zh
	pop zl
	ret
