avr: rewrote timer code (split into timer and basetimer).

Only basetimer depends on hardware and clock speed. Works onj AtTiny 84
at 1 MHz and 8 MHz.
This commit is contained in:
Martin Preuss
2024-09-13 21:39:24 +02:00
parent 6ff68b848c
commit cdcb4e2b3e
5 changed files with 276 additions and 136 deletions

View File

@@ -3,6 +3,7 @@
<gwbuild> <gwbuild>
<subdirs> <subdirs>
basetimer
bmp280 bmp280
cny70 cny70
com2 com2

View File

@@ -0,0 +1,12 @@
<?xml?>
<gwbuild>
<extradist>
main.asm
</extradist>
</gwbuild>

View File

@@ -0,0 +1,188 @@
; ***************************************************************************
; copyright : (C) 2024 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. *
; ***************************************************************************
;
; The base timer makes sure that "onSystemTimerTick" is called about every
; 100ms.
; The setup depends on hardware and clock.
;
; ***************************************************************************
; data
.dseg
baseTimerModuleData:
baseTimerModuleReloadValue: .byte 1
baseTimerModuleTickCounter: .byte 1
baseTimerTicksSinceLastRun: .byte 2
baseTimerModuleData_end:
; ***************************************************************************
; code
.cseg
BASETIMER_BEGIN:
; ---------------------------------------------------------------------------
; @rotuine BaseTimer_Init @global
;
; @clobbers r16, r17, x
BaseTimer_Init: ; setup timer for IRQ every 100ms
; reset data in SDRAM
ldi xh, HIGH(baseTimerModuleData)
ldi xl, LOW(baseTimerModuleData)
ldi r16, 0
ldi r17, (baseTimerModuleData_end-baseTimerModuleData)
rcall Utils_FillSram
ldi r16, (1<<CS02) | (1<<CS00) ; Prescaler 1024
out TCCR0B, r16
ldi r16, (1<<WGM01) ; CTC mode
out TCCR0A, r16
ldi r16, (1<<OCF0A) ; clear pending interrupts
out TIFR0, r16
ldi r16, (1<<OCIE0A)
out TIMSK0, r16
;
; Settings for clock 1Mhz (default)
; use timer0 with OCR0A=98-1 (irq every 97.65625 millisecs), baseTimerModuleReloadValue 1
;
.if clock == 1000000
; CMP-A interrupt about every 100ms
ldi r16, 98-1 ; (1,000,000/1024)/10 = 97.65625
out OCR0A, r16
ldi r16, 1
sts baseTimerModuleReloadValue, r16
.endif
;
; Settings for clock 8Mhz
; use timer0 with OCR0A=78 (irq every 9.984 millisecs), baseTimerModuleReloadValue 10
;
.if clock == 8000000
; CMP-A interrupt about every 10ms
ldi r16, 78-1
out OCR0A, r16
ldi r16, 10
sts baseTimerModuleReloadValue, r16
.endif
sec
ret
; ---------------------------------------------------------------------------
; @routine BaseTimer_Fini @global
;
BaseTimer_Fini:
ret
; @end
; ---------------------------------------------------------------------------
; @routine BaseTimer_Run @global
;
; @return CFLAG set if something done, cleared otherwise
; @clobbers all
BaseTimer_Run:
push r15
in r15, SREG
cli
lds r24, baseTimerTicksSinceLastRun
lds r25, baseTimerTicksSinceLastRun+1
clr r16 ; replace with 0 for next IRQ
sts baseTimerTicksSinceLastRun, r16
sts baseTimerTicksSinceLastRun+1, r16
out SREG, r15 ; restore global IRQ flag
pop r15
sbiw r25:r24, 0
clc ; flag "nothing done"
breq BaseTimer_Run_End
BaseTimer_Run_loop: ; for every timer tick
push r24
push r25
rcall onSystemTimerTick
pop r25
pop r24
sbiw r25:r24, 1
brne BaseTimer_Run_loop
sec
BaseTimer_Run_End:
ret
; @end
; ---------------------------------------------------------------------------
; @routine baseTimerIrqOC0A @isr
;
; OC0A interrupt handler
;
; Increments baseTimerModuleTickCounter, if it reaches 0 then baseTimerTicksSinceLastRun
; is also incremented and the baseTimerModuleTickCounter reloaded.
; The rest is done outside ISR baseTimerTicksSinceLastRun in BaseTimer_Run.
baseTimerIrqOC0A:
push r15
in r15, SREG
push r24
push r25
lds r24, baseTimerModuleTickCounter
dec r24
breq baseTimerIrqOC0A_timerElapsed
sts baseTimerModuleTickCounter, r24
rjmp baseTimerIrqOC0A_end
baseTimerIrqOC0A_timerElapsed:
lds r24, baseTimerModuleReloadValue ; reload counter
sts baseTimerModuleTickCounter, r24
lds r24, baseTimerTicksSinceLastRun
lds r25, baseTimerTicksSinceLastRun+1
adiw r25:r24, 1
sts baseTimerTicksSinceLastRun, r24
sts baseTimerTicksSinceLastRun+1, r25
baseTimerIrqOC0A_end:
pop r25
pop r24
out SREG, r15
pop r15
reti
; @end
BASETIMER_END:
.equ MODULE_SIZE_BASETIMER = BASETIMER_END-BASETIMER_BEGIN

View File

@@ -38,9 +38,8 @@ CPRO_WriteSysStats:
lds r17, com2Interrupts+1 lds r17, com2Interrupts+1
st X+, r17 st X+, r17
lds r17, timerInterrupts clr r17
st X+, r17 ; timer interrupts st X+, r17 ; timer interrupts (not used anymore)
lds r17, timerInterrupts+1
st X+, r17 st X+, r17
pop xl pop xl
pop xh pop xh

View File

@@ -26,9 +26,7 @@
timerModuleData: timerModuleData:
timerModuleTickCounter: .byte 1 timerModuleTickCounter: .byte 1
timerTicksSinceLastRun: .byte 2
timerModuleCounterSecs: .byte 4 timerModuleCounterSecs: .byte 4
timerInterrupts: .byte 2
timerModuleData_end: timerModuleData_end:
@@ -44,15 +42,11 @@ TIMER_BEGIN:
; --------------------------------------------------------------------------- ; ---------------------------------------------------------------------------
; Timer_Init ; @routine Timer_Init
; ;
; IN: ; @clobbers r16, r17, x
; - nothing
; OUT:
; - nothing
; USED: r16, r17, x
Timer_Init: ; setup timer for IRQ every 100ms Timer_Init:
; reset data in SDRAM ; reset data in SDRAM
ldi xh, HIGH(timerModuleData) ldi xh, HIGH(timerModuleData)
ldi xl, LOW(timerModuleData) ldi xl, LOW(timerModuleData)
@@ -60,107 +54,63 @@ Timer_Init: ; setup timer for IRQ every 100ms
ldi r17, (timerModuleData_end-timerModuleData) ldi r17, (timerModuleData_end-timerModuleData)
rcall Utils_FillSram rcall Utils_FillSram
; CTC mode (WGM2:0=2, OCR0A=value, OCF0A Flag =1, -> IRQ_OC0A ldi r16, 10 ; every sec
sts timerModuleTickCounter, r16
; 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
rcall timerInitTimers rcall timerInitTimers
ret ret
; @end
; --------------------------------------------------------------------------- ; ---------------------------------------------------------------------------
; Timer_Fini ; @routine Timer_Fini
; ;
; IN:
; - nothing
; OUT:
; - nothing
; USED:
Timer_Fini: Timer_Fini:
ret ret
; @end
; --------------------------------------------------------------------------- ; ---------------------------------------------------------------------------
; Timer_Run ; @routine onSystemTimerTick
; ;
; IN: ; @return CFLAG set if something done, cleared otherwise
; - nothing ; @clobbers all
; OUT:
; - CFLAG: set if something done, cleared otherwise
; USED: r15, r16, r24, r25 (more depending on called routines)
Timer_Run: onSystemTimerTick:
in r15, SREG lds r16, timerModuleTickCounter
cli dec r16
lds r24, timerTicksSinceLastRun breq onSystemTimerTick_SecondElapsed
lds r25, timerTicksSinceLastRun+1 sts timerModuleTickCounter, r16
clr r16 ; replace with 0 for next IRQ rjmp onSystemTimerTick_call
sts timerTicksSinceLastRun, r16
sts timerTicksSinceLastRun+1, r16 onSystemTimerTick_SecondElapsed:
out SREG, r15 ; restore global IRQ flag ldi r16, 10 ; reload counter (10=every sec)
sbiw r25:r24, 0 sts timerModuleTickCounter, r16
clc ; flag "nothing done" ldi xl, LOW(timerModuleCounterSecs)
breq Timer_Run_End ldi xh, HIGH(timerModuleCounterSecs)
Timer_Run_loop: ; for every occurred 100ms irq rcall Utils_IncrementCounter32 ; inc uptime counter
push r24
push r25 onSystemTimerTick_call:
rcall timerRunTimers rcall timerRunTimers
rcall onEvery100ms rcall onEvery100ms
pop r25
pop r24
lds r16, timerModuleTickCounter
inc r16
cpi r16, 10
brcc Timer_Run_SecondElapsed
sts timerModuleTickCounter, r16
rjmp Timer_Run_loop_end
Timer_Run_SecondElapsed:
clr r16
sts timerModuleTickCounter, r16
; push r24
; push r25
; rcall timerRunTimers
; pop r25
; pop r24
Timer_Run_loop_end:
sbiw r25:r24, 1
brne Timer_Run_loop
sec
Timer_Run_End:
ret ret
; @end
; --------------------------------------------------------------------------- ; ---------------------------------------------------------------------------
; Set timer value. ; @routine Timer_SetValue @global
; ;
; Set timer value.
; Setting a timer to 0 effectively stops the timer. ; Setting a timer to 0 effectively stops the timer.
; ;
; IN: ; @param r16 new timer value (low)
; - r16: new timer value (low) ; @param r17 new timer value (high)
; - r17: new timer value (high) ; @param X pointer to timer value in SRAM
; - X : pointer to timer value in SRAM ; @clobbers X
; OUT:
; - nothing
; REGS: X
Timer_SetValue: Timer_SetValue:
push r15 push r15
@@ -171,17 +121,17 @@ Timer_SetValue:
out SREG, r15 out SREG, r15
pop r15 pop r15
ret ret
; @end
; --------------------------------------------------------------------------- ; ---------------------------------------------------------------------------
; @routine Timer_SetValueTo1s @global
;
; Set timer value to 1s. ; Set timer value to 1s.
; ;
; IN: ; @param X pointer to timer value in SRAM
; - X : pointer to timer value in SRAM ; @clobbers X
; OUT:
; - nothing
; REGS: X
Timer_SetValueTo1s: Timer_SetValueTo1s:
push r16 push r16
@@ -192,10 +142,18 @@ Timer_SetValueTo1s:
pop r17 pop r17
pop r16 pop r16
ret ret
; @end
; ---------------------------------------------------------------------------
; @routine timerInitTimers
;
; Init timers in table.
;
; @clobbers all
timerInitTimers: timerInitTimers:
ldi zl, LOW(timerList*2) ldi zl, LOW(timerList*2)
ldi zh, HIGH(timerList*2) ldi zh, HIGH(timerList*2)
@@ -220,13 +178,18 @@ timerInitTimers_writeInitial:
timerInitTimers_end: timerInitTimers_end:
ret ret
; @end
; ---------------------------------------------------------------------------
; @routine timerRunTimers
;
; Run timers in table.
;
; @clobbers all
timerRunTimers: timerRunTimers:
ldi xl, LOW(timerModuleCounterSecs)
ldi xh, HIGH(timerModuleCounterSecs)
rcall Utils_IncrementCounter32
ldi zl, LOW(timerList*2) ldi zl, LOW(timerList*2)
ldi zh, HIGH(timerList*2) ldi zh, HIGH(timerList*2)
timerRunTimers_loop: timerRunTimers_loop:
@@ -260,20 +223,23 @@ timerRunTimers_reachedZero:
rjmp timerRunTimers_loop rjmp timerRunTimers_loop
timerRunTimers_end: timerRunTimers_end:
ret ret
; @end
; --------------------------------------------------------------------------- ; ---------------------------------------------------------------------------
; read time table entry. ; @routine timerReadTableEntry
; ;
; IN: ; read timer table entry.
; - Z : pointer to time list entry (suitable for LPM) ;
; @param Z pointer to time list entry (suitable for LPM)
; OUT: ; OUT:
; - r19:r18: handler routine ; @return r19:r18 handler routine
; - X : SRAM address for counter ; @return X SRAM address for counter
; - r21:r20: initial value ; @return r21:r20 initial value
; - r22 : flags ; @return r22 flags
; - r23 : reserved ; @return r23 reserved
timerReadTableEntry: timerReadTableEntry:
lpm xl, Z+ ; SRAM address of counter lpm xl, Z+ ; SRAM address of counter
lpm xh, Z+ lpm xh, Z+
@@ -284,45 +250,19 @@ timerReadTableEntry:
lpm r20, Z+ ; initial value lpm r20, Z+ ; initial value
lpm r21, Z+ lpm r21, Z+
ret ret
; @end
; ---------------------------------------------------------------------------
; @routine timerCallR19R18
; Call route at address r19:r18
timerCallR19R18: timerCallR19R18:
push r18 push r18
push r19 push r19
ret ret
; @end
; ---------------------------------------------------------------------------
; OC0A interrupt handler
;
; Called every 100 milliseconds, increments timerTicksSinceLastRun. The rest is done outside ISR
; in Timer_Run.
timerIrqOC0A:
push r15
in r15, SREG
push r24
push r25
lds r24, timerTicksSinceLastRun
lds r25, timerTicksSinceLastRun+1
adiw r25:r24, 1
sts timerTicksSinceLastRun, r24
sts timerTicksSinceLastRun+1, r25
lds r24, timerInterrupts
lds r25, timerInterrupts+1
adiw r25:r24, 1
sts timerInterrupts, r24
sts timerInterrupts+1, r25
pop r25
pop r24
out SREG, r15
pop r15
reti