; ***************************************************************
; *
; * LED-PWM-Dimmer fr atmolight (vdr)
; *
; * Externe Beschaltung:
; * PORTA0-A5: RGB RGB
; *
; * PB0..PB2 : Startadresse 1. RGB Kanal (invertiert)
; * PD5..PD7 : Startadresse 2. RGB Kanal (invertiert)
; * Wenn eine Adresse auf 0x07 steht, wird sie aus dem EEPROM
; * gelesen, Format siehe Ende dieser Datei!
; *
; * Quarz 14,7456MHz an XTAL1/XTAL2
; * MAX232 soll von der RS232 lesen und an Pin2=RXD liefern
; *
; * Version 0.0.1-15
; * Simon Canins <simon (at) canins.de>
; *
; ***************************************************************


.NOLIST
.INCLUDE "m8def.inc"
.LIST
;
;
; Register:
;
.DEF addr=R0;   Benutzt zum Auslesen der Startadresse
.DEF buffer=R1; Zeichenpuffer serielle Kommunikation
;
;------Sollwerte der Farben
.DEF R1L=R2
.DEF R1H=R3

.DEF G1L=R4
.DEF G1H=R5

.DEF B1L=R6
.DEF B1H=R7

.DEF R2L=R8
.DEF R2H=R9

.DEF G2L=R10
.DEF G2H=R11

.DEF B2L=R12
.DEF B2H=R13

.DEF temp=R16; Temp-Register f. Hauptprogramm
.DEF temp2=R17; Temp-Register und Parameter fr Gamma-Funktion
.DEF sreg_buffer=R18 ; Zum zwischenspeichern von SREG im Interrupt
.DEF itemph=R20; Temp-Register f. Interruptroutine
.DEF itempl=R21
.DEF itemp2=R22
.DEF rs232state=R23; Statemachine RS232 Kommunikation

.DEF pwmH=R24	; Rckgabewert der Gamma-Funktion H
.DEF pwmL=R25	; Rckgabewert der Gamma-Funktion L


; X=R26/27: Z�ler fr PWM
; Y=R28/29: Adressen
; Z=R30/31: Pointer zum Auslesen der Gamma-Tabelle
;
; Konstanten
;
;.EQU freq=11059200; Taktfrequenz
.EQU freq= 14745600; Taktfrequenz
;.EQU freq=16000000; Taktfrequenz
;.EQU freq=8000000; Taktfrequenz

.EQU baud=38400; Baudrate fuer RS232
//.EQU baud=19200; Baudrate fuer RS232
.EQU bddiv=(freq/(16*baud))-1; Baudratenteiler

.EQU AusgPort=PORTC ; Welcher Port soll zur Ausgabe verwendet werden? (6bits)
.EQU AusgDDR=DDRC

;
; Code segment startet hier
;
.CSEG
;
; Reset- und Interrupt-Vektoren
;
	rjmp Start; RESET
	reti; 
	reti; 
	reti; 
	reti; 
	reti; 
	rjmp TIMER1COMPA; TIMER1 OCIE1A
	reti; 
	reti; 
	rjmp TIMER0OVL; 
	reti; 
	reti; 
	reti; 
	reti; 
	reti; 
	reti; 
	reti; 
	reti; 
	reti; 
	reti;

;*****************************
;     Interruptroutinen
;*****************************


;-------------------------------------------------------------------------------
;       PWM Erzeugung

TIMER1COMPA:
	in sreg_buffer,SREG ; SREG sichern

	ldi itemph, 0; Timer1 wieder auf 0 stellen
	out TCNT1H, itemph
	out TCNT1L, itemph

	sbiw XL, 2;  PWM Counter um 1 erniedrigen

	ldi itemp2, 0xFF; Byte, das sp�er auf Port ausgegeben werden soll vorbereiten

	;  R1---------------------------------------

	cp XL, R1L;  Sollwert mit PWM Counter vergleichen
	cpc XH, R1H
	brlo pwmR1
	cbr itemp2, 1  ; Wenn Z�ler gr�er, dann Bit setzen

pwmR1:

	;  G1---------------------------------------

	cp XL, G1L;  Sollwert mit PWM Counter vergleichen
	cpc XH, G1H
	brlo pwmG1
	cbr itemp2, 2  ; Wenn Z�ler gr�er, dann Bit setzen

pwmG1:

	;  B1---------------------------------------
	
	cp XL, B1L;  Sollwert mit PWM Counter vergleichen
	cpc XH, B1H
	brlo pwmB1
	cbr itemp2, 4  ; Wenn Z�ler gr�er, dann Bit setzen

pwmB1:

	;  R2---------------------------------------
	
	cp XL, R2L;  Sollwert mit PWM Counter vergleichen
	cpc XH, R2H
	brlo pwmR2
	cbr itemp2, 8 ; Wenn Z�ler gr�er, dann Bit setzen

pwmR2:

	;  G2---------------------------------------
	
	cp XL, G2L;  Sollwert mit PWM Counter vergleichen
	cpc XH, G2H
	brlo pwmG2
	cbr itemp2, 16  ; Wenn Z�ler gr�er, dann Bit setzen

pwmG2:

	;  B2---------------------------------------
	
	cp XL, B2L;  Sollwert mit PWM Counter vergleichen
	cpc XH, B2H
	brlo pwmB2
	cbr itemp2, 32  ; Wenn Z�ler gr�er, dann Bit setzen

pwmB2:

	out AusgPort, itemp2; auf Port ausgeben


	cpi XL, 0
	brne int_weiter1; wenn noch nicht 0, dann weiter, sonst wieder auf max.Wert setzen
	cpi XH, 0
	brne int_weiter1; wenn noch nicht 0, dann weiter, sonst wieder auf max.Wert setzen

	ldi XH, HIGH(2047); Wenn Counter auf 0 abgelaufen, dann wieder auf
	ldi XL, LOW(2047);  Maximalwert setzen

int_weiter1:

	ldi itempl, 1 ; Prfen, ob PWM Counter den Wert 2 erreicht hat
	ldi itemph, 0
	cp itempl, XL
	cpc itemph, XH
	brne int_weiter2; Wenn ja, dann auf 2047 setzen, so werden 2 Counterdurchl�ft
					; erreicht, einer mit geraden Zahlen, einer mit ungeraden
					; das verringert das Flimmern

	ldi XH, HIGH(2046)
	ldi XL, LOW(2046)

int_weiter2:


	out SREG,sreg_buffer ; SREG wiederherstellen
	reti

;--------------------------------------------------------------------------------
;            RS232 Timeout

TIMER0OVL:

	clr rs232state  ; Statemachine wieder auf Anfang setzen

	reti


;*****************************
;     Hauptprogramm
;*****************************


Start:
;
; Stack initialisieren
;
	ldi temp,HIGH(RAMEND)
	out SPH,temp
	ldi temp,LOW(RAMEND)
	out SPL,temp
;
; Ports initialisieren
;
	ldi temp,0xFF; Port als Ausgang festlegen (PWM-Ausgabe)
	out AusgDDR,temp

	ldi temp, 0x00; Port auf 0 setzen
	out AusgPort, temp

	ldi temp, 0xF8
	out DDRB, temp; Port als Eingang festlegen (Adresseinstellung RGB1)
	ldi temp, 0x07
	out PORTB, temp;Pullups aktivieren

	ldi temp, 0x1F
	out DDRD, temp; Port als Eingang festlegen (Adresseinstellung RGB2)
	ldi temp, 0xE0
	out PORTD, temp;Pullups aktivieren


;
; Sollwerte initialisieren
;
	ldi temp, 0x00

	mov R1L, temp
	mov R1H, temp
	mov G1L, temp
	mov G1H, temp
	mov B1L, temp
	mov B1H, temp

	mov R2L, temp
	mov R2H, temp
	mov G2L, temp
	mov G2H, temp
	mov B2L, temp
	mov B2H, temp
;
; USART initialisieren
;
	ldi temp, bddiv; Setze Baudrate
	out UBRRL, temp

	ldi temp, 0x00
	out UCSRA, temp

	sbi UCSRB, RXEN;  RX einschalten
//	sbi UCSRB, TXEN

	ldi temp, (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0)
	out UCSRC, temp

	clr rs232state; Statemachine auf Startbit setzen

;
; EEPROM: Adresse initialisieren
;

//	ldi temp, LOW(Adresse)
	ldi temp, 0
	out EEARL, temp	
//	ldi temp, HIGH(Adresse)
	out EEARH, temp

;
; Timer0 initialisiern RS232 RX Timeout
;

	ldi temp, (1<<CS02) ; Prescaler auf 256 -> Overflow bei 16MHz alle 4,096ms
	out TCCR0, temp

;
; Timer1 initialisiern (PWM Erzeugung)
;

	ldi temp, 0
	out TCCR1A, temp

	out OCR1AH, temp; OCR1AH setzen, alle wieviel Take soll der Int aufgerufen werden
	ldi temp, 70
	out OCR1AL, temp

	ldi temp, (1<<CS10) | (1<<CS00); Timer mit Prozessortakt laufen lassen
	out TCCR1B, temp



	ldi temp, (1<<OCIE1A) | (1<<TOV0); Interrupts freischalten
	out TIMSK, temp

	ldi XH, HIGH(2046); PWM Counter initialisieren
	ldi XL, LOW(2046)


	sei; Interrupts aktivieren

;
; Hauptschleife:
;

//rjmp state_weiter
loop:

	sbis UCSRA, RXC; Solange kein Zeichen empfangen wird, weiterwarten
	rjmp loop

	; Wenn Zeichen empfangen wurde

	rcall zeichen; Zeichen empfangen, Unterprogramm aufrufen!

	rjmp loop	; Endlosschleife fortsetzen


;*******************************
;     Gamma Korrektur
;	temp2 = Helligkeitssollwert 0..255
; 	pwmH, pwmL = Ergebnis, fr PWM
;*******************************

; Gamma Tabelle gamma=2,5
gammatab: .DW 0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,2,2,2,3,3,4,4,4,5,6,6,7,7,8,9,10,11,11,12,13,14,15,16,18,19,20,21,23,24,25,27,28,30,31,33,35,37,38,40,42,44,46,48,51,53,55,57,60,62,65,67,70,72,75,78,81,84,87,90,93,96,99,103,106,109,113,116,120,124,127,131,135,139,143,147,151,156,160,164,169,173,178,183,187,192,197,202,207,212,217,223,228,233,239,245,250,256,262,268,274,280,286,292,298,305,311,317,324,331,338,344,351,358,365,373,380,387,395,402,410,417,425,433,441,449,457,465,474,482,491,499,508,516,525,534,543,552,562,571,580,590,599,609,619,628,638,648,658,669,679,689,700,710,721,732,743,754,765,776,787,799,810,822,833,845,857,869,881,893,905,918,930,943,955,968,981,994,1007,1020,1033,1047,1060,1074,1088,1101,1115,1129,1143,1157,1172,1186,1201,1215,1230,1245,1260,1275,1290,1305,1321,1336,1352,1367,1383,1399,1415,1431,1448,1464,1480,1497,1514,1530,1547,1564,1582,1599,1616,1634,1651,1669,1687,1705,1723,1741,1759,1778,1796,1815,1833,1852,1871,1890,1909,1929,1948,1968,1987,2007,2027,2047

gammakorr:

	ldi ZL, LOW(2*gammatab) ; auf Startadresse der Gamma-Tabelle setzen
	ldi ZH, HIGH(2*gammatab)
	
	ldi pwmH, 0x00 ; pwmH auf 0 setzen (als Temp-Variable)
	lsl temp2	   ; temp2 mit 2 multiplizieren
	adc pwmH, pwmH ; 16bit-Teil des  shifts in pwmH ablegen

	add ZL, temp2  ; Helligkeitssollwert*2 zur Adresse addieren
	adc ZH, pwmH

	lpm pwmL, Z+   ; PWM-Wert aus der Gamma-Tabelle laden
	lpm pwmH, Z
	
	reti


;*******************************
;     Zeichen empfangen (RS232)
;*******************************

zeichen:

	ldi temp, 0x00	; Timeout wieder zurcksetzen (-> Interrupt)
	out TCNT0, temp

	in buffer, UDR ; Zeichen lesen
	

	; Statemachine
		
; Erkennung des Headers

	ldi temp, 0x00 ;statemachine: Startbyte
	cp temp, rs232state
	breq startbyte;

	ldi temp, 0x01 ;statemachine: StartL
	cp temp, rs232state
	breq startL;

	ldi temp, 0x02 ;statemachine: StartH
	cp temp, rs232state
	breq startH

	ldi temp, 0x03 ;statemachine: LEN
	cp temp, rs232state
	breq LEN

	rjmp state_weiter
	
; Bearbeiten der gefundenen Bytes

startbyte:
	ldi temp, 0xFF
	cp buffer, temp
	breq ok_state1; Wenn richtiges Byte gefunden
	rjmp fail; Sonst von vorne beginnen

startL:
	ldi temp, 0x0
	cp buffer, temp
	breq ok_state1; Wenn richtiges Byte gefunden
	rjmp fail; Sonst von vorne beginnen

startH:
	ldi temp, 0x0
	cp buffer, temp
	breq ok_state1; Wenn richtiges Byte gefunden
	rjmp fail; Sonst von vorne beginnen

LEN:
	ldi temp, 0x0F
	cp buffer, temp
	breq ok_state1; Wenn richtiges Byte gefunden
//	rjmp fail; Sonst von vorne beginnen

fail:; Fehler bei der Bearbeitung, -> neu beginnn
	ldi rs232state, 0x00

	rjmp end

ok_state1: ; steht nur hier, da branch nicht weit genug kommt
	rjmp ok

; Verarbeitung mit den Farb-Bytes fortsetzen

state_weiter:

	in YL, PINB   ; Startadresse 1. RGB Kanal einlesen
	in YH, PIND   ; Startadresse 2. RGB Kanal einlesen
	lsr YH			 ; Startadresse 2. RGB Kanal 5 bits nach rechts schieben
	lsr YH
	lsr YH
	lsr YH
	lsr YH
	andi YL, 0x07    ; relevante bits herausfiltern
	andi YH, 0x07    ; relevante bits herausfiltern

	cpi YL, 0x07     ; Wenn Adresse == 7, dann aus dem EEPROM lesen
	brne adr_weiter

	sbi EECR, EERE   ; EEPROM Lesen Vorbereiten
    in YL, EEDR      ; EEPROM lesen
	andi YL, 0x07    ; relevante Bits herausfiltern

adr_weiter:			

	cpi YH, 0x07	 ; Wenn Adresse == 7, dann aus dem EEPROM lesen
	brne adr_weiter2
	
	sbi EECR, EERE   ; EEPROM Lesen Vorbereiten
    in YH, EEDR      ; EEPROM lesen
	lsr YH			 ; Shift um 3 nach rechts
	lsr YH
	lsr YH
	andi YH, 0x07    ; relevante Bits herausfiltern

adr_weiter2:


;--------------------------RGB1----------------------------

	ldi temp, 0x04 ;statemachine: R1
	cp temp, rs232state
	brne R1next    ; Wenn dieses Byte nicht R1 ist dann Bearbeitung berspringen

	mov temp2, buffer ; Gamma Korrektur anwenden
	rcall gammakorr

	; Startadresse berprfen
	cpi YL, 0x00  ; 1. RGB Kanal auf Adresse 0 ?
	brne R1weiter ; wenn nicht, Abspeichern berspringen
	
	mov R1L, pwmL ; wenn ja, dort abspeichern
	mov R1H, pwmH

R1weiter:         ; wenn 1. RGB Kanal nicht auf Adresse 0 hier weitermachen

	cpi YH, 0x00  ; 2. RGB Kanal auf Adresse 0 ?
	brne ok_state2; wenn nicht, Bearbeitung beenden

	mov R2L, pwmL ; wenn ja, dort abspeichern
	mov R2H, pwmH
	rjmp ok		  ; Bearbeitung beenden

R1next:
	ldi temp, 0x05 ;statemachine: G1
	cp temp, rs232state
	brne G1next

	mov temp2, buffer ; Gamma Korrektur anwenden
	rcall gammakorr

	; Startadresse berprfen
	cpi YL, 0x00  
	brne G1weiter 
	
	mov G1L, pwmL 
	mov G1H, pwmH

G1weiter:         

	cpi YH, 0x00  
	brne ok_state2

	mov G2L, pwmL 
	mov G2H, pwmH
	rjmp ok		  


G1next:	
	ldi temp, 0x06 ;statemachine: B1
	cp temp, rs232state
	brne B1next

	mov temp2, buffer ; Gamma Korrektur anwenden
	rcall gammakorr

	; Startadresse berprfen
	cpi YL, 0x00  
	brne B1weiter 
	
	mov B1L, pwmL 
	mov B1H, pwmH

B1weiter:         

	cpi YH, 0x00  
	brne ok_state2

	mov B2L, pwmL 
	mov B2H, pwmH
	rjmp ok		  

ok_state2: ; steht nur hier, da branch nicht weit genug kommt
	rjmp ok

;--------------------------RGB2----------------------------
B1next:
	ldi temp, 0x07 ;statemachine: R2
	cp temp, rs232state
	brne R2next

	mov temp2, buffer ; Gamma Korrektur anwenden
	rcall gammakorr

	; Startadresse berprfen
	cpi YL, 0x01  
	brne R2weiter 
	
	mov R1L, pwmL 
	mov R1H, pwmH

R2weiter:         
	cpi YH, 0x01  
	brne ok_state3

	mov R2L, pwmL 
	mov R2H, pwmH
	rjmp ok		  

R2next:
	ldi temp, 0x08 ;statemachine: G2
	cp temp, rs232state
	brne G2next

	mov temp2, buffer ; Gamma Korrektur anwenden
	rcall gammakorr

	; Startadresse berprfen
	cpi YL, 0x01  
	brne G2weiter 
	
	mov G1L, pwmL 
	mov G1H, pwmH

G2weiter:         
	cpi YH, 0x01  
	brne ok_state3

	mov G2L, pwmL 
	mov G2H, pwmH
	rjmp ok		  


G2next:
	ldi temp, 0x09 ;statemachine: B2
	cp temp, rs232state
	brne B2next

	mov temp2, buffer ; Gamma Korrektur anwenden
	rcall gammakorr

	; Startadresse berprfen
	cpi YL, 0x01  
	brne B2weiter
	
	mov B1L, pwmL 
	mov B1H, pwmH

B2weiter:         

	cpi YH, 0x01  
	brne ok_state3

	mov B2L, pwmL 
	mov B2H, pwmH
	rjmp ok		  


ok_state3: ; steht nur hier, da branch nicht weit genug kommt
	rjmp ok


;--------------------------RGB3----------------------------

B2next:
	ldi temp, 0x0A ;statemachine: R3
	cp temp, rs232state
	brne R3next

	mov temp2, buffer ; Gamma Korrektur anwenden
	rcall gammakorr

	; Startadresse berprfen
	cpi YL, 0x02  
	brne R3weiter 
	
	mov R1L, pwmL 
	mov R1H, pwmH

R3weiter:         

	cpi YH, 0x02  
	brne ok_state3

	mov R2L, pwmL 
	mov R2H, pwmH
	rjmp ok		  


R3next:
	ldi temp, 0x0B ;statemachine: G3
	cp temp, rs232state
	brne G3next

	mov temp2, buffer ; Gamma Korrektur anwenden
	rcall gammakorr

	; Startadresse berprfen
	cpi YL, 0x02  
	brne G3weiter 
	
	mov G1L, pwmL 
	mov G1H, pwmH

G3weiter:         

	cpi YH, 0x02  
	brne ok_state3

	mov G2L, pwmL 
	mov G2H, pwmH
	rjmp ok		  


G3next:
	ldi temp, 0x0C ;statemachine: B3
	cp temp, rs232state
	brne B3next; wenn kein Zustand passt, neu anfangen

	mov temp2, buffer ; Gamma Korrektur anwenden
	rcall gammakorr

	; Startadresse berprfen
	cpi YL, 0x02  
	brne B3weiter 
	
	mov B1L, pwmL 
	mov B1H, pwmH

B3weiter:         

	cpi YH, 0x02  
	brne ok_state3

	mov B2L, pwmL 
	mov B2H, pwmH
	rjmp ok		  

;--------------------------RGB4----------------------------

B3next:
	ldi temp, 0x0D ;statemachine: R4
	cp temp, rs232state
	brne R4next

	mov temp2, buffer ; Gamma Korrektur anwenden
	rcall gammakorr

	; Startadresse berprfen
	cpi YL, 0x03  
	brne R4weiter 
	
	mov R1L, pwmL 
	mov R1H, pwmH

R4weiter:         

	cpi YH, 0x03  
	brne ok_state4

	mov R2L, pwmL 
	mov R2H, pwmH
	rjmp ok		  


R4next:
	ldi temp, 0x0E ;statemachine: G4
	cp temp, rs232state
	brne G4next

	mov temp2, buffer ; Gamma Korrektur anwenden
	rcall gammakorr

	; Startadresse berprfen
	cpi YL, 0x03  
	brne G4weiter 
	
	mov G1L, pwmL 
	mov G1H, pwmH

G4weiter:         

	cpi YH, 0x03  
	brne ok_state4

	mov G2L, pwmL 
	mov G2H, pwmH
	rjmp ok		  


G4next:
	ldi temp, 0x0F ;statemachine: B4
	cp temp, rs232state
	brne B4next; wenn kein Zustand passt, neu anfangen

	mov temp2, buffer ; Gamma Korrektur anwenden
	rcall gammakorr

	; Startadresse berprfen
	cpi YL, 0x03  
	brne B4weiter 
	
	mov B1L, pwmL 
	mov B1H, pwmH

B4weiter:         

	cpi YH, 0x03  
	brne ok_state4

	mov B2L, pwmL 
	mov B2H, pwmH
	rjmp ok		  

ok_state4: ; steht nur hier, da branch nicht weit genug kommt
	rjmp ok


;--------------------------RGB5----------------------------

B4next:
	ldi temp, 0x10 ;statemachine: R5
	cp temp, rs232state
	brne R5next

	mov temp2, buffer ; Gamma Korrektur anwenden
	rcall gammakorr

	; Startadresse berprfen
	cpi YL, 0x04  
	brne R5weiter 
	
	mov R1L, pwmL 
	mov R1H, pwmH

R5weiter:         

	cpi YH, 0x04  
	brne ok_state4

	mov R2L, pwmL 
	mov R2H, pwmH
	rjmp ok		  


R5next:
	ldi temp, 0x11 ;statemachine: G5
	cp temp, rs232state
	brne G5next

	mov temp2, buffer ; Gamma Korrektur anwenden
	rcall gammakorr

	; Startadresse berprfen
	cpi YL, 0x04
	brne G5weiter 
	
	mov G1L, pwmL 
	mov G1H, pwmH

G5weiter:         

	cpi YH, 0x04  
	brne ok_state4

	mov G2L, pwmL 
	mov G2H, pwmH
	rjmp ok		  


G5next:
	ldi temp, 0x12 ;statemachine: B5
	cp temp, rs232state
	brne B5next; wenn kein Zustand passt, neu anfangen

	mov temp2, buffer ; Gamma Korrektur anwenden
	rcall gammakorr

	; Startadresse berprfen
	cpi YL, 0x04 
	brne B5weiter 
	
	mov B1L, pwmL 
	mov B1H, pwmH

B5weiter:         

	cpi YH, 0x04  
	brne ok_state4

	mov B2L, pwmL 
	mov B2H, pwmH
	rjmp ok		  

B5next:
	rjmp fail

fail_state:	; nur forward
	rjmp  fail

ok:; Byte erfolgreich bearbeitet
	inc rs232state ; Statemachine weiterz�len

	ldi temp, 0x15 ; Obergrenze berprfen
	cp rs232state, temp
	brne end       ; Wenn letztes Byte noch nicht erreicht, weitermachen

	rjmp fail      ; sonst Statemachine zurcksetzen und neu beginnen mit n�hster �ertragung

end:
	ret

.ESEG;------------------------------EEPROM--------------------------------------

Adresse: .DB 0 ; Startadresse auf dem RS232 Bus
               ; Format: --xxxyyy
               ; xxx Startadresse 2. RGB Kanal
               ; yyy Startadresse 1. RGB Kanal
