;*** Measure the width of an external pulse with an AVR Mega8
;;
;;   PWM sginal from R/C receiver. One 1-2ms pulse every 20ms.
;;   R/C PWM signal connected to ICP (PortB, Pin0).
;;   Mega8 running at 4Mhz.
;;   Demo code sets C0/C1 to move linear actuator left or right.
;;   Note that if upper 8 bits of ICR1 are not all zero, 
;;   then pulse width exceeds valid range.
;;   -rkumar at hyperreal dot org


.include "m8def.inc"

.org 0x0000				; Reset vector
rjmp reset
.org 0x0005				; Timer1 Capture Event Interupt vector
rjmp TIM1_CAPT



reset:
ldi r16, low(RAMEND)	; Set up stack pointer on reset
out SPL, r16
ldi r16, high(RAMEND)
out SPH, r16

ldi r16, (1<<ICES1)|(1<<CS11)|(1<<CS10)
out TCCR1B, r16			; Set clock prescaler to 32
						; Also set the Input Capture Edge Select bit to 1
						; (trigger on rising edge)

ldi r16, 1<<ICF1
out TIFR, r16			; Clear ICF1, Clear pending interupts.

ldi r16, 1<<TICIE1		; Set bit 4.
out TIMSK, r16			; Enable Timer1 capture event interupt.
sei						; Enable global interupts.

ser r16					; Set all bits in r16.
out DDRD, r16			; Set PortD as output.
;out DDRB, r16			; Set PortB as output.
out DDRC, r16			; Set PortC as output (instead of PortB!)

cbi DDRB, PB0			; Set PB0 (ICP) as input.


loop:					; Loop forever! Wait for interupt!
rjmp loop



; Timer1 Capture Handler_________________________________________________
TIM1_CAPT:
						; We don't need to perserve registers, since they
						; are not used outside this ISR. But be careful
						; when extending this code. Note that this ISR
						; returns from different places!



in r20, ICR1L			; Read Input Capture Register to r20/21
in r21, ICR1H


						; Invert the edge select bit.. This is NOT the best way to do this..
						; We have 32 registers, and we should use them.
						; However, it is unclear right now which registers our main loop
						; will need.

in  r16, TCCR1B			; Read Timer1 Control Register B into r16.
bst r16, ICES1			; Store edge select bit in T.
bld r17, ICES1			; Load edge select bit from T into r17.
com r17					; Invert bits in r17.
bst r17, ICES1			; Store edge select bit in T.
bld r16, ICES1			; Now we have the inverted the edge select bit in r16.
out TCCR1B, r16			; Set Timer1 Control Register with inverted edge select bit.


clr r17
out TCNT1H, r17			; Clear Timer1
out TCNT1L, r17

sbrs r16, ICES1			; In r16, if edge select bit==0 (which means we entered on rising edge)
reti					; then return from interupt and wait for falling edge.


; If we reach this point in the ISR, it means we entered on a negative edge.
; The pulse width is already stored in r20/21.

cpi r21, 0				; compaire r21 with 0
    brne case_rcerror		;    if not zero, then handle error
cpi r20, 128			; else, compare r20 with 128
    brsh case_rcerror		;    if greater or equal than 128, then handle error 
cpi r20, 66				; else, compare r20 with 66
    brlo case_right		;    if less than6, move actuator right
cpi r20, 102			; else, compare r20 with 102
    brsh case_left			; if same or higher than 102, move actuator left
default:				; else...
    cbi PORTC, PC1			; clear PB2 and PB4...
    cbi PORTC, PC0			; ...to ensure the actuator is not moving!
    com r20				; Invert bits (led's connected backwards)
    out PORTD, r20			; Write lower 8 bits of Timer1 ICR to PortD


;clr r16				; clearing Timer1 here should be unnecessary	
;out TCNT1H, r16		; clear Timer1
;out TCNT1L, r16

reti



; case_right: Move the Linear Actuator to the right______________________
case_right:
cbi PORTC, PC0			; Ensure that PB4 is not set
sbi PORTC, PC1			; Set PB2 to move the actuator right.

com r20					; Invert bits (led's connected backwards)
out PORTD, r20			; Write lower 8 bits of Timer1 ICR to PortD
reti


; case_left: Move the Linear Actuator to the left________________________
case_left:
cbi PORTC, PC1			; Ensure that PB2 is not set
sbi PORTC, PC0			; Set PB4 to move the actuator left.

com r20					; Invert bits (led's connected backwards)
out PORTD, r20			; Write lower 8 bits of Timer1 ICR to PortD
reti


; case_rcerror: Handle RC receiver errors________________________________
case_rcerror:
cbi PORTC, PC0
cbi PORTC, PC1

clr r16;
out PORTD, r16;
reti