Files
aqhomecontrol/avr/timer.asm
Martin Preuss 87b31a4a4b COM. TIMER: Fixed a bug (note to self: INC/DEC set Z flag, but not C flag!!)
- added COM_EnqueueComSendStats
- check for high ATTN line before sending packets
2023-01-26 18:57:20 +01:00

223 lines
4.5 KiB
NASM

; ***************************************************************************
; defs
.equ TIMER_FLAGS_100MS = 1
.equ TIMER_FLAGS_1S = 2
; ***************************************************************************
; data
.dseg
timerModuleData:
timerModuleTickCounter: .byte 1 ; only low byte used
timerModuleFlags: .byte 1
timerModuleCounter10s: .byte 1
timerModuleCounter1m: .byte 1
timerModuleCounterSecs: .byte 4
timerModuleData_end:
; ***************************************************************************
; code
.cseg
; ***************************************************************************
; Timer_Init
;
; IN:
; - nothing
; OUT:
; - nothing
; USED: r16, r17, x
Timer_Init: ; setup timer for 15.2588 interrupts per second (e.g. every 65.5 ms)
; reset data in SDRAM
ldi xh, HIGH(timerModuleData)
ldi xl, LOW(timerModuleData)
ldi r16, 0
ldi r17, (timerModuleData_end-timerModuleData)
rcall Utils_FillSram
; CTC mode (WGM2:0=2, OCR0A=value, OCF0A Flag =1, -> IRQ_OC0A
; CMP-A interrupt about every 100ms
ldi r16, (1<<CS02) | (1<<CS00) ; Prescaler 1024
out TCCR0B, r16
ldi r16, (1<<WGM01) ; CTC mode
out TCCR0A, r16
ldi r16, 98-1 ; (1,000,000/1024)/10 = 97.65625
out OCR0A, r16
ldi r16, (1<<OCF0A) ; clear pending interrupts
out TIFR0, r16
ldi r16, (1<<OCIE0A)
out TIMSK0, r16
ret
; ***************************************************************************
; Timer_Fini
;
; IN:
; - nothing
; OUT:
; - nothing
; USED:
Timer_Fini:
ret
; ***************************************************************************
; Timer_Run
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if something done, reset otherwise
; USED: r15, r16, r17 (more depending on called routines)
Timer_Run:
in r15, SREG
cli
clr r16
lds r17, timerModuleFlags
sts timerModuleFlags, r16
out SREG, r15 ; restore global IRQ flag
mov r16, r17
andi r16, TIMER_FLAGS_100MS
breq Timer_Run_l1
push r17
rcall onEvery100ms
pop r17
Timer_Run_l1:
mov r16, r17
andi r16, TIMER_FLAGS_1S
breq Timer_Run_l2
; another 1s passed, invoke callback, check for 10s and 1m
push r17
rcall onEverySecond
pop r17
; 1s
lds r16, timerModuleCounter10s
inc r16
sts timerModuleCounter10s, r16
cpi r16, 10
brcs Timer_Run_check1m
clr r16
sts timerModuleCounter10s, r16
push r17
rcall onEvery10s
pop r17
Timer_Run_check1m:
; 1m
lds r16, timerModuleCounter1m
inc r16
sts timerModuleCounter1m, r16
cpi r16, 60
brcs Timer_Run_l2
clr r16
sts timerModuleCounter1m, r16
push r17
rcall onEveryMinute
pop r17
Timer_Run_l2:
sec
tst r17
brne Timer_Run_end
clc
Timer_Run_end:
ret
; ***************************************************************************
; OC0A interrupt handler
;
; Called every 100 milliseconds, sets flag TIMER_FLAGS_100MS.
; Increments an internal counter. If that counter reaches 10 the seconds counter is incremented and a the flag
; TIMER_FLAGS_1S is set.
timerIrqOC0A:
push r15
in r15, SREG
push r16
push r17
lds r17, timerModuleFlags
ori r17, TIMER_FLAGS_100MS
lds r16, timerModuleTickCounter
inc r16
cpi r16, 10
brcc timerIrq2_l1
sts timerModuleTickCounter, r16
rjmp timerIrq2_l2
timerIrq2_l1: ; increment seconds
; reset 100ms counter
clr r16
sts timerModuleTickCounter, r16
; increment seconds
push xh
push xl
push r18
push r19
push r20
push r21
push r22
ldi xh, HIGH(timerModuleCounterSecs)
ldi xl, LOW(timerModuleCounterSecs)
ld r18, x+
ld r19, x+
ld r20, x+
ld r21, x
ldi r22, 1
add r18, r22
dec r22
adc r19, r22
adc r20, r22
adc r21, r22
st x, r21
st -x, r20
st -x, r19
st -x, r18
pop r22
pop r21
pop r20
pop r19
pop r18
pop xl
pop xh
ori r17, TIMER_FLAGS_1S
timerIrq2_l2:
sts timerModuleFlags, r17 ; store new timer flags
pop r17
pop r16
out SREG, r15
pop r15
reti