timer.inc
author Tero Marttila <terom@paivola.fi>
Sun, 20 Apr 2014 23:51:57 +0300
changeset 80 5254ba612630
parent 32 7ceb76b5a104
permissions -rw-r--r--
dmx-web: slightly better RGB colorpicker control..
;; vim: filetype=avr
;;
;; Timer unit control and use
;;

.equ TIMER_FLAGS = GPIOR0

;; Timer0
; Compare output mode
.set TIMER0_COMA = 0b00			; null
.set TIMER0_COMB = 0b00			; null

; Waveform Generation Mode (triplet low/high)
.set TIMER0_WGML = 0b10			; CTC
.set TIMER0_WGMH = 0b0			; CTC

; Clock Source
.set TIMER0_CS = 0b101			; 1/1024

;; Timer1
; Waveform Generation Mode (nibble low/high)
.set TIMER1_WGML = 0b00			; CTC
.set TIMER1_WGMH = 0b01			; CTC

; Clock Source
.set TIMER1_CS = 0b101			; 1/1024

; Flags
.equ TIMER1_BUSY = 1

.set SLEEP_MODE = 0b000			; Idle

Timer_Init:
Timer0_Init:
		; OC0A/B disconnected from output
		; No PWM mode
		ldi			r16, (TIMER0_COMA << COM0A0) | (TIMER0_COMB << COM0B0) | (TIMER0_WGML << WGM00)
		out			TCCR0A, r16

		; Clear
		ldi			r16, 0
		out			OCR0A, r16
		out			OCR0B, r16
		out			TCCR0B, r16

		; Enable compare interrupt
		ldi			r16, (1 << OCIE0A)
		sts			TIMSK0, r16

Timer1_Init:
		; OC1A/B disconnected from output
		; No PWM mode
		poke		[TCCR1A, r16, (0b00 << COM1A0) | (0b00 << COM1B0) | (TIMER1_WGML << WGM10)]

		; Clear
		poke		[TCCR1B, r16, 0]
		poke		[TCCR1C, r16, 0]

		; Enable compare 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

;; Timer0 is recurring; this starts it running, and it keeps hitting OC0A periodically
;;  Input: r16 (period, in 1k-cycles)
Timer0_Start:
	; Initialize timer
		; set CTC trigger from r16
		out			OCR0A, r16

		; clear counter
		ldi			r16, 0
		out			TCNT0, r16

	; Start
		; WGM
		; Clock Source
		ldi			r16, (TIMER0_WGMH << WGM02) | (TIMER0_CS << CS00)
		out			TCCR0B, r16

		ret

Timer0_Read8:
		in			r16, TCNT0

		ret

;; Timer0 Compare A interrupt handler
Timer_OC0A:
		in			r0, SREG

		; Run callback
		rcall		TIMER0_CB_A

		out			SREG, r0
		reti

;; Timer1 is one-shot; this starts it running, and it is then stopped once it hits OC1A
Timer1_Start:
	; Initialize timer
		poke		[TCNT1H, r16, high(0)]
		poke		[TCNT1L, r16, low(0)]

	; Set flag
		sbi			TIMER_FLAGS, TIMER1_BUSY
	
	; Start
		; WGM
		; Clock Source
		poke		[TCCR1B, r16, (TIMER1_WGMH << WGM12) | (TIMER1_CS << CS10)]

		ret

Timer1_Stop:
		; WGM
		; Clock off
		poke		[TCCR1B, r16, (TIMER1_WGMH << WGM12) | (0b00 << CS10)]
		
	; Clear flag
		cbi			TIMER_FLAGS, TIMER1_BUSY

		ret

;; Timer1 Compare A interrupt handler
Timer_OC1A:
		in			r0, SREG
	
	; Stop timer
		rcall		Timer1_Stop

		out			SREG, r0
		reti

;; 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)

	;; Continue

;; Count to X
Timer_Sleep:
	; Set TOP
		sts			OCR1AH, XH
		sts			OCR1AL, XL

	; Start timer
		rcall		Timer1_Start

	; Wait for timer to complete
_timer1_sleep:
		sleep
		
		sbic		TIMER_FLAGS, TIMER1_BUSY
		rjmp		_timer1_sleep

	; Done
		ret

;; Update timer for given timeout
Timer_Update:
	; Set TOP
		sts			OCR1AH, XH
		sts			OCR1AL, XL
	
	; Check timer
		lds			YL, TCNT1L
		lds			YH, TCNT1H
		
		cp			YL, XL
		cpc			YH, XH

		brlo		timer_up_out

	; Update
	; XXX: figure out a better way to do this...
		ldi			r16, 0
		subi		XL, 2
		sbc			XH, r16

		sts			TCNT1L, XL
		sts			TCNT1H, XH

timer_up_out:
	; Done
		ret