; *************************************************************************** ; copyright : (C) 2023 by Martin Preuss ; email : martin@libchipcard.de ; ; *************************************************************************** ; * This file is part of the project "AqHome". * ; * Please see toplevel file COPYING of that project for license details. * ; *************************************************************************** ; *************************************************************************** ; defs .equ TIMER_FLAGS_IF_ADDR = 1 ; *************************************************************************** ; data .dseg timerModuleData: timerModuleTickCounter: .byte 1 timerModuleCounterSecs: .byte 4 timerModuleData_end: ; *************************************************************************** ; code .cseg TIMER_BEGIN: ; --------------------------------------------------------------------------- ; @routine Timer_Init ; ; @clobbers r16, r17, x Timer_Init: ; reset data in SDRAM ldi xh, HIGH(timerModuleData) ldi xl, LOW(timerModuleData) ldi r16, 0 ldi r17, (timerModuleData_end-timerModuleData) rcall Utils_FillSram ldi r16, 10 ; every sec sts timerModuleTickCounter, r16 rcall timerInitTimers ret ; @end ; --------------------------------------------------------------------------- ; @routine Timer_Fini ; Timer_Fini: ret ; @end ; --------------------------------------------------------------------------- ; @routine onSystemTimerTick ; ; @return CFLAG set if something done, cleared otherwise ; @clobbers all onSystemTimerTick: lds r16, timerModuleTickCounter dec r16 breq onSystemTimerTick_SecondElapsed sts timerModuleTickCounter, r16 rjmp onSystemTimerTick_call onSystemTimerTick_SecondElapsed: ldi r16, 10 ; reload counter (10=every sec) sts timerModuleTickCounter, r16 ldi xl, LOW(timerModuleCounterSecs) ldi xh, HIGH(timerModuleCounterSecs) rcall Utils_IncrementCounter32 ; inc uptime counter ; sbi DEBUG_LED_DDR, DEBUG_LED_PINNUM ; out ; sbi DEBUG_LED_PORT_IN, DEBUG_LED_PINNUM ; toggle onSystemTimerTick_call: rcall timerRunTimers rcall onEvery100ms ret ; @end ; --------------------------------------------------------------------------- ; @routine Timer_SetValue @global ; ; Set timer value. ; Setting a timer to 0 effectively stops the timer. ; ; @param r16 new timer value (low) ; @param r17 new timer value (high) ; @param X pointer to timer value in SRAM ; @clobbers X Timer_SetValue: push r15 in r15, SREG cli st X+, r16 st X+, r17 out SREG, r15 pop r15 ret ; @end ; --------------------------------------------------------------------------- ; @routine Timer_SetValueTo1s @global ; ; Set timer value to 1s. ; ; @param X pointer to timer value in SRAM ; @clobbers X Timer_SetValueTo1s: push r16 push r17 ldi r16, 10 clr r17 rcall Timer_SetValue pop r17 pop r16 ret ; @end ; --------------------------------------------------------------------------- ; @routine timerInitTimers ; ; Init timers in table. ; ; @clobbers all timerInitTimers: ldi zl, LOW(timerList*2) ldi zh, HIGH(timerList*2) clr r16 ; run var for pos in time table clr r17 ; 0 for adc timerInitTimers_loop: rcall timerReadTableEntry mov r18, xl or r18, xh breq timerInitTimers_end mov r18, r20 or r18, r21 breq timerInitTimers_writeInitial add r20, r16 ; add counter pos in table so that not all timers elapse at the same time adc r21, r17 timerInitTimers_writeInitial: st X+, r20 st X, r21 inc r16 inc r16 rjmp timerInitTimers_loop timerInitTimers_end: ret ; @end ; --------------------------------------------------------------------------- ; @routine timerRunTimers ; ; Run timers in table. ; ; @clobbers all timerRunTimers: ldi zl, LOW(timerList*2) ldi zh, HIGH(timerList*2) timerRunTimers_loop: rcall timerReadTableEntry mov r16, xl or r16, xh breq timerRunTimers_end mov r16, r22 andi r16, TIMER_FLAGS_IF_ADDR breq timerRunTimers_l1 ; no need to check address lds r16, com2Address ; check address tst r16 breq timerRunTimers_loop ; no address, ignore counter timerRunTimers_l1: ld r24, X+ ld r25, X sbiw r25:r24, 1 brcs timerRunTimers_loop ; overflow, so already was zero, ignore entry breq timerRunTimers_reachedZero ; reached zero st X, r25 st -X, r24 rjmp timerRunTimers_loop timerRunTimers_reachedZero: st X, r21 ; reset initial value st -X, r20 push zl push zh rcall timerCallR19R18 pop zh pop zl rjmp timerRunTimers_loop timerRunTimers_end: ret ; @end ; --------------------------------------------------------------------------- ; @routine timerReadTableEntry ; ; read timer table entry. ; ; @param Z pointer to time list entry (suitable for LPM) ; OUT: ; @return r19:r18 handler routine ; @return X SRAM address for counter ; @return r21:r20 initial value ; @return r22 flags ; @return r23 reserved timerReadTableEntry: lpm xl, Z+ ; SRAM address of counter lpm xh, Z+ lpm r18, Z+ ; routine (low) lpm r19, Z+ ; routine (high) lpm r22, Z+ ; flags lpm r23, Z+ ; reserved lpm r20, Z+ ; initial value lpm r21, Z+ ret ; @end ; --------------------------------------------------------------------------- ; @routine timerCallR19R18 ; Call route at address r19:r18 timerCallR19R18: push r18 push r19 ret ; @end TIMER_END: .equ MODULE_SIZE_TIMER = TIMER_END-TIMER_BEGIN