;*** 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 writes lower 8 bits of Timer1/ICR1 to PortD.
;;   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

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.
cbi DDRB, PB0			; Set PB0 (ICP) as input.

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

; Timer1 Capture Handler_________________________________________________
				; 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 two different places, depending on ICES1!

;;push r16			; Preserve r16
;;in r16, SREG			; Save MCU status register
;;push r16

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.

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

;;pop r16			; Remember this isn't the only place we return from the ISR.
;;out SREG, r16
;;pop r16