;; vim: filetype=avr
;;
;; Timer unit control and use
;;
; Waveform Generation Mode (nibble low/high)
.set TIMER_WGML = 0b00
.set TIMER_WGMH = 0b01
; Clock Source
.set TIMER_CS = 0b101
.equ TIMER_FLAGS = GPIOR0
.equ TIMER_BUSY = 1
.set SLEEP_MODE = 0b000 ; Idle
Timer_Init:
; OC1A/B disconnected from output
; No PWM mode
poke [TCCR1A, r16, (0b00 << COM1A0) | (0b00 << COM1B0) | (TIMER_WGML << WGM10)]
; Clear
poke [TCCR1B, r16, 0]
poke [TCCR1C, r16, 0]
; Enable timer overflow interrupt
poke [TIMSK1, r16, (1 << OCIE1A)]
Sleep_init:
; Select sleep mode
; Enable `sleep`
poke [SMCR, r16, (SLEEP_MODE << SM0) | (1 << SE)]
; Disable ADC
poke [SMCR, r16, (1 << PRTWI) | (1 << PRUSART0) | (1 << PRADC)]
ret
Timer_Start:
; Initialize timer
poke [TCNT1H, r16, high(0)]
poke [TCNT1L, r16, low(0)]
; Set flag
sbi TIMER_FLAGS, TIMER_BUSY
; WGM
; Clock Source
poke [TCCR1B, r16, (TIMER_WGMH << WGM12) | (TIMER_CS << CS10)]
ret
Timer_Stop:
; WGM
; Clock off
poke [TCCR1B, r16, (TIMER_WGMH << WGM12) | (0b00 << CS10)]
; Clear flag
cbi TIMER_FLAGS, TIMER_BUSY
ret
;; Timer Compare 1A interrupt handler
Timer_OC1A:
in r0, SREG
; Stop timer
rcall Timer_Stop
out SREG, r0
reti
;; Count to X
Timer_Sleep:
; Set TOP
sts OCR1AH, XH
sts OCR1AL, XL
; Start timer
rcall Timer_Start
; Wait for timer to complete
_timer_sleep:
sleep
sbic TIMER_FLAGS, TIMER_BUSY
rjmp _timer_sleep
; Done
ret
;; Prime the timer and sleep for 1s
Timer_Sleep_1s:
; Initialize counter to 16k cycles
ldi XH, high(16 * 1024)
ldi XL, low(16 * 1024)
; Start timer
rjmp Timer_Sleep