From f631d462c1e2a54ab9a9516548ca75b75fde63a0 Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Mon, 20 Feb 2023 23:47:56 +0100 Subject: [PATCH] TIMER: improved module, added some callbacks. --- avr/timer.asm | 306 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 222 insertions(+), 84 deletions(-) diff --git a/avr/timer.asm b/avr/timer.asm index 74c44c1..679fbe0 100644 --- a/avr/timer.asm +++ b/avr/timer.asm @@ -6,6 +6,14 @@ .equ TIMER_FLAGS_100MS = 1 .equ TIMER_FLAGS_1S = 2 +.equ TIMER_CALLBACK_10S = 0x01 +.equ TIMER_CALLBACK_30S = 0x02 +.equ TIMER_CALLBACK_1M = 0x04 +.equ TIMER_CALLBACK_15M = 0x08 +.equ TIMER_CALLBACK_30M = 0x10 +.equ TIMER_CALLBACK_1H = 0x20 +.equ TIMER_CALLBACK_12H = 0x40 +.equ TIMER_CALLBACK_1D = 0x80 @@ -17,9 +25,17 @@ timerModuleData: timerModuleTickCounter: .byte 1 ; only low byte used timerModuleFlags: .byte 1 -timerModuleCounter10s: .byte 1 -timerModuleCounter1m: .byte 1 timerModuleCounterSecs: .byte 4 + +timerModuleDerivedCounters: ; order of the following vars matters!! +timerModuleCounterFor10s: .byte 1 ; change Timer_IncrementCounters when changing the +timerModuleCounterFor1m: .byte 1 ; order here! +timerModuleCounterFor15m: .byte 1 +timerModuleCounterFor30m: .byte 1 +timerModuleCounterFor1h: .byte 1 +timerModuleCounterFor12h: .byte 1 +timerModuleCounterFor1d: .byte 1 + timerModuleData_end: @@ -71,7 +87,7 @@ Timer_Init: ; setup timer for 15.2588 interrupts per second (e.g. eve -; *************************************************************************** +; --------------------------------------------------------------------------- ; Timer_Fini ; ; IN: @@ -85,81 +101,211 @@ Timer_Fini: -; *************************************************************************** +; --------------------------------------------------------------------------- ; Timer_Run ; ; IN: ; - nothing ; OUT: -; - CFLAG: set if something done, reset otherwise -; USED: r15, r16, r17 (more depending on called routines) +; - CFLAG: set if something done, cleared otherwise +; USED: r15, r16, r17, R19 (more depending on called routines) Timer_Run: in r15, SREG cli - lds r17, timerModuleFlags - clr r16 + lds r17, timerModuleFlags ; get timer flags + clr r16 ; replace with 0 for next IRQ 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: + andi r16, TIMER_FLAGS_100MS ; timer irq occurred? + brne Timer_Run_100ms_passed ; yes, go handle + out SREG, r15 ; restore global IRQ flag + clc ; nothing done + ret +Timer_Run_100ms_passed: 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, 30 ; check for every 30s - brne Timer_Run_l4 - push r16 - push r17 - rcall onEvery30s - pop r17 - pop r16 -Timer_Run_l4: - cpi r16, 60 - brcs Timer_Run_l2 - clr r16 - sts timerModuleCounter1m, r16 - push r17 - rcall onEvery30s - rcall onEveryMinute - pop r17 - -Timer_Run_l2: + brne Timer_Run_1s_passed + out SREG, r15 ; restore global IRQ flag + rcall onEvery100ms ; only call this one + sec + ret +Timer_Run_1s_passed: + clr r19 ; flags for additional callbacks to be called + rcall Timer_IncrementCounters ; 1s passed, handle depending counters, sample callback flags + out SREG, r15 ; restore global IRQ flag + mov r16, r19 + rcall Timer_CallOnEveryHandlers sec - tst r17 - brne Timer_Run_end - clc -Timer_Run_end: ret -; *************************************************************************** +; --------------------------------------------------------------------------- +; Call "onEvery*" handlers according to given flags. +; +; IN: +; - R16: flags +; OUT: +; - nothing +; REGS: depending on called routines, expect clobbering of all registers + +Timer_CallOnEveryHandlers: + push r16 + rcall onEvery100ms ; always call this one + rcall onEverySecond ; and this + pop r16 + tst r16 ; any flag set? + breq Timer_CallOnEveryHandlers_done ; nope, nothing more to call + mov r17, r16 + andi r17, TIMER_CALLBACK_10S + breq Timer_CallOnEveryHandlers_l1 + push r16 + rcall onEvery10s + pop r16 +Timer_CallOnEveryHandlers_l1: + mov r17, r16 + andi r17, TIMER_CALLBACK_30S + breq Timer_CallOnEveryHandlers_l2 + push r16 + rcall onEvery30s + pop r16 +Timer_CallOnEveryHandlers_l2: + mov r17, r16 + andi r17, TIMER_CALLBACK_1M + breq Timer_CallOnEveryHandlers_l3 + push r16 + rcall onEveryMinute + pop r16 +Timer_CallOnEveryHandlers_l3: + mov r17, r16 + andi r17, TIMER_CALLBACK_15M + breq Timer_CallOnEveryHandlers_l4 + push r16 + rcall onEvery15m + pop r16 +Timer_CallOnEveryHandlers_l4: + mov r17, r16 + andi r17, TIMER_CALLBACK_30M + breq Timer_CallOnEveryHandlers_l5 + push r16 + rcall onEvery30m + pop r16 +Timer_CallOnEveryHandlers_l5: + mov r17, r16 + andi r17, TIMER_CALLBACK_1H + breq Timer_CallOnEveryHandlers_l6 + push r16 + rcall onEvery1h + pop r16 +Timer_CallOnEveryHandlers_l6: + mov r17, r16 + andi r17, TIMER_CALLBACK_12H + breq Timer_CallOnEveryHandlers_l7 + push r16 + rcall onEvery12h + pop r16 +Timer_CallOnEveryHandlers_l7: + mov r17, r16 + andi r17, TIMER_CALLBACK_1D + breq Timer_CallOnEveryHandlers_done + push r16 + rcall onEvery1d + pop r16 +Timer_CallOnEveryHandlers_done: + ret + + + +; --------------------------------------------------------------------------- +; Increments the list of dependent counters and sets flag in R19 accordingly. +; +; IN: +; - R19: flags to add to +; OUT: +; - R19: flags for callback handlers to be called +; REGS: R16, R19, X + +Timer_IncrementCounters: + ldi xl, LOW(timerModuleDerivedCounters) ; points to first counter: timerModuleCounterFor10s + ldi xh, HIGH(timerModuleDerivedCounters) + clr r19 + + ldi r17, 10 ; overflow after 10s + ldi r18, TIMER_CALLBACK_10S + rcall timerInc8CheckVar + brcc Timer_IncrementCounters_done + + ldi r17, 3 ; overflow after 3*10s + ldi r18, TIMER_CALLBACK_30S + rcall timerInc8CheckVar + brcc Timer_IncrementCounters_done + + ldi r17, 2 ; overflow after 2*30s + ldi r18, TIMER_CALLBACK_1M + rcall timerInc8CheckVar + brcc Timer_IncrementCounters_done + + ldi r17, 30 ; overflow after 30*1m + ldi r18, TIMER_CALLBACK_30M + rcall timerInc8CheckVar + brcc Timer_IncrementCounters_done + + ldi r17, 2 ; overflow after 2*30m + ldi r18, TIMER_CALLBACK_1H + rcall timerInc8CheckVar + brcc Timer_IncrementCounters_done + + ldi r17, 12 ; overflow after 12*1h + ldi r18, TIMER_CALLBACK_12H + rcall timerInc8CheckVar + brcc Timer_IncrementCounters_done + + ldi r17, 2 ; overflow after 2*12h + ldi r18, TIMER_CALLBACK_1D + rcall timerInc8CheckVar + brcc Timer_IncrementCounters_done +Timer_IncrementCounters_done: + ret + + + +; --------------------------------------------------------------------------- +; Increment an 8 bit counter and check result. +; +; If the incremented counter is equal or greater than the given value the counter +; is reset, the given flag is ORed to the flags and carry flag is set on return. +; Otherwise the counter is just incremented and carry flag cleared. +; +; IN: +; - X: ptr to counter +; - R17: value to compare against +; - R18: flag to add on overflow +; - R19: flags to add to +; OUT: +; - CFLAG set if overflow occurred, cleared otherwise +; - X: points to next counter (advanced by one byte) +; REGS: R16, R19, X + +timerInc8CheckVar: + ld r16, X + inc r16 + cp r16, r17 + brcs timerInc8CheckVar_stillSmaller + clr r16 + st X+, r16 + or r19, r18 + sec + ret +timerInc8CheckVar_stillSmaller: + st X+, r16 + clc + ret + + + + +; --------------------------------------------------------------------------- ; OC0A interrupt handler ; ; Called every 100 milliseconds, sets flag TIMER_FLAGS_100MS. @@ -188,30 +334,22 @@ timerIrq2_l1: ; 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 + ldi xh, HIGH(timerModuleCounterSecs) + ldi xl, LOW(timerModuleCounterSecs) + ldi r18, 1 + ld r16, X ; byte 0 + adc r16, r18 ; inc by 1 + dec r18 ; doesn't affect carry flag! (r18 becomes 0 for following ADC) + st X+, r16 + ld r16, X ; byte 1 + adc r16, r18 + st X+, r16 + ld r16, X ; byte 2 + adc r16, r18 + st X+, r16 + ld r16, X ; byte 3 + adc r16, r18 + st X+, r16 pop r18 pop xl pop xh