;********************************************************************************
;*** This program is written by Ralph Willekes. It can make a colorfull show  ***
;*** for a RGBLED or cluster. It drives three LEDs or a single RGB LED in PWM ***
;*** mode from 0 to 100%. Please use NORMAL values for the current limiting   ***
;*** resistors as this is NO such thing as a high current low duty cycle      ***
;*** pulse source or something. If you break your expensive LEDs it's your    ***
;*** problem, not mine. U can modify this code if you want, but please put my ***
;*** name somewhere if you really use it.                       (nov 14 2003) ***
;********************************************************************************

.include "2313def.inc"

.def	temp 	= r16
.def 	STtmp	= r17

.def	status	= r18

.def	fan_cnt	= r19
.def	counter = r20

.def	r_byte	= r21

.def	rd		= r23
.def	gn		= r24
.def	bl		= r25

.def	rd_tmp	= r26
.def	gn_tmp	= r27
.def	bl_tmp	= r28

.equ	SPD_VAL	= 25	;SPD_VAL * 0,197 sec for a whole sequence when a 8MHz 
						;crystal is used. SPD_VAL = 0 -> 50 sec.
 
.org $000
rjmp RESET
rjmp RESET
rjmp RESET
rjmp RESET
rjmp RESET
rjmp RESET

.org $006
rjmp tmr0_ovf

.org $007
rjmp Rx_byte

rjmp RESET
rjmp RESET
rjmp RESET

;********************************************************************************
;*** The reset function sets all things that need to be set in order to run   ***
;*** the program. The ports are set up, the counter is initialised and the    ***
;*** interupts are given free.                                                ***
;********************************************************************************


RESET:
cli
ldi temp, 	LOW(RAMEND) ; lower byte
out SPL,	temp 		; to stack pointer

ldi	rd,	1
ldi gn, 1
ldi bl, 1
ldi status,	1
ldi fan_cnt, 0

;ports
clr	temp
out PORTD, 	temp
out DDRB, 	temp

ldi	temp,	254
out DDRD, 	temp
ser	temp
out PORTB, 	temp
sbi	portD,  6		;zet fan aan!

;counter/timer
ldi temp,	1
out tccr0, 	temp	;set the counter to CK speed
ldi temp,	2
out TIMSK,	temp	;set the counter interupt on

;UART
ldi temp,	191	
out UBRR,	temp	;set baudrate = 2400
ldi	temp,	144	
out	UCR,	temp	;set Rx enable + Rx interupt
clr	status

;interupt enable
sei

rjmp	main

;********************************************************************************
;*** The UART receive interupt routine will collect the data and tests if it  ***
;*** is correct. A correct frame will have $AA $Rd $Gn $Bl $55. These must be ***
;*** sent separate, I don't know why... HELP!!!                               ***
;********************************************************************************

Rx_byte:
in STtmp, SREG	;copy SREG to temp

in	r_byte,	UDR

cpi	status, 1
breq gr0
cpi	status, 2
breq gr1
cpi	status, 3
breq gr2
cpi	status, 4
brsh gr3

cpi	r_byte,	0xAA
brne rec_end
inc status
rjmp rec_end

gr0:
mov	rd_tmp, r_byte
inc	status
rjmp rec_end

gr1:
mov	gn_tmp, r_byte
inc	status
rjmp rec_end

gr2:
mov	bl_tmp, r_byte
inc	status
rjmp rec_end

gr3:
cpi r_byte,	0x55
brne	clr_stat
mov	rd,	rd_tmp
mov	gn,	gn_tmp
mov	bl,	bl_tmp

clr_stat:
clr	status

rec_end:
out SREG, STtmp	;put the SREG in it's last condition before interupt routine
reti

;********************************************************************************
;*** The counter will take care of the PWM driving of the LEDs.               ***
;********************************************************************************

tmr0_ovf: 		;begin of counter/timer overflow interupt routine

in STtmp, SREG	;copy SREG to temp

inc counter

rd_c:
cpi	rd, 0			;if rd = 0
breq rd_off			;	jump to rd_off
cp	rd,	counter	
brlo rd_off			;if rd >= counter then
sbi	portD, 5		;	turn LED on
rjmp gn_c			;
rd_off:				;else
cbi	portD, 5		;	turn LED off
					;end if
gn_c:
cpi	gn, 0			;same as above, but for green LED
breq gn_off
cp	gn,	counter		
brlo gn_off
sbi	portD, 4
rjmp bl_c
gn_off:
cbi	portD, 4

bl_c:
cpi	bl, 0			;same as above, but for blue LED
breq bl_off
cp	bl,	counter		
brlo bl_off
sbi	portD, 3
rjmp ovf_end
bl_off:
cbi	portD, 3

ovf_end:
out SREG, STtmp	;put the SREG in it's last condition before interupt routine
reti			;return to main program




;********************************************************************************
;*** The main program checks the counter/timer value to see if it changes.    ***
;*** When it has changed it sets or clears the outputs of PortB in order to   ***
;*** create a three channel PWM signal which outputs correspond to the values ***
;*** of the rd, gn and bl registers. Invert for anode or PNP transistor drive.***
;********************************************************************************

main:


rjmp main