Skip to content

Commit d8e9e52

Browse files
committed
new millis-optimized timer interrupt
1 parent 1f137ec commit d8e9e52

File tree

5 files changed

+39
-29
lines changed

5 files changed

+39
-29
lines changed

src/ArduinoShrink.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ inline void delay(uint32_t msec)
88
{
99
register __uint24 ms asm ("r24") = msec;
1010
asm volatile (
11-
"rcall %x1\n"
11+
"%~call %x1\n"
1212
: "+r"(ms)
1313
: "i"(delay_impl)
1414
: "r19", "r20", "r21" // clobbers

src/micros.S

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,20 @@
55
#define __SFR_OFFSET 0
66
#include <avr/io.h>
77

8-
;struct {
9-
; uint32_t t0_ovfl;
10-
; uint8_t ovfl_pad;
11-
;} t0_millis;
12-
13-
148
; to force t0_isr to get linked in
159
.global t0_ovfl_isr
1610

1711
.global micros_raw
1812
micros_raw:
1913
ldi ZL, lo8(t0_millis)
2014
ldi ZH, hi8(t0_millis)
21-
1:
15+
_reload:
2216
in r22, TCNT0
2317
ld r23, Z
2418
ldd r24, Z+1
2519
ldd r25, Z+2
2620
in r0, TCNT0
2721
sub r0, r22 ; TCNT0 overflow?
28-
brcs 1b
22+
brcs _reload
2923
ret
24+

src/millis.S

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
GLABEL millis_impl
1111
ldi ZL, lo8(t0_millis)
1212
ldi ZH, hi8(t0_millis)
13-
_reload:
13+
_reload:
1414
ld r22, Z
1515
ldd r23, Z+1
1616
ldd r24, Z+2

src/millis.c

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,31 @@
55
#include <avr/io.h>
66
#include "as_common.h"
77

8+
#define CPU_MHZ (F_CPU / 1000000)
9+
810
extern uint32_t micros_raw();
911
uint32_t micros()
1012
{
1113
register uint32_t u asm("r22");
12-
//asm ("%~call %x1" : "=r" (u) : "i"(micros_raw) : "r30", "r31" );
13-
//return u * 4;
14-
asm (
15-
"%~call %x1 \n"
16-
"ldi r30, lo8(T0_SCALE + 2) \n"
17-
"rcall lsl4_r22_r30 \n"
18-
: "=r" (u) : "i"(micros_raw) : "r30", "r31"
19-
);
20-
return u;
14+
asm ("%~call %x1" : "=r" (u) : "i"(micros_raw) : "r30", "r31" );
15+
// split into lower 8 & upper 24-bits
16+
uint8_t t0 = u & 0xFF;
17+
__uint24 u3 = u >> 8;
18+
19+
//return (u3 * 1000) + (t0 * (uint8_t)(T0_PRESCALE / CPU_MHZ));
20+
// shift + add saves 24B vs * 1000, asm would be a bit smaller
21+
return ( ((u3 << 7) - ((u3 << 1) + u3)) << 3 ) +
22+
(t0 * (uint8_t)(T0_PRESCALE / CPU_MHZ));
2123
}
2224

2325
extern uint32_t millis_impl();
2426
uint32_t millis()
2527
{
28+
register uint32_t m asm("r22");
29+
asm ("%~call %x1" : "=r" (m) : "i"(millis_impl) : "r30", "r31" );
2630
return millis_impl();
2731
}
2832

29-
#define CPU_MHZ (F_CPU / 1000000)
3033
#define MICROS_PER_T0_OVFL ((T0_PRESCALE * 256) / CPU_MHZ)
3134
#define MILLIS_INC (MICROS_PER_T0_OVFL / 1000)
3235
#define FRACT_INC ((MICROS_PER_T0_OVFL % 1000) >> 2)
@@ -40,9 +43,6 @@ void init_millis()
4043
asm ( ".global FRACT_INC\n");
4144
asm ( ".equ FRACT_INC, %0\n" :: "M" (FRACT_INC) );
4245

43-
// scaling factor for t0 vs 16Mhz
44-
uint8_t t0_scale = log2(16000000/F_CPU);
45-
asm ( ".equ T0_SCALE, %0\n" :: "M" (t0_scale) );
4646
TIMSK0 = _BV(TOIE0); // enable T0 overflow interrupt
4747
}
4848

src/t0_ovfl_isr.S

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@ GLABEL t0_ovfl_isr
2323

2424
; this is an optimized asm version of the Arduino core timer overflow
2525
; github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/wiring.c
26-
; 8 bits are used instead of 7 for better precision at non 2^n F_CPU
26+
; uses 8 bits of t0_fract instead of 7 for more precision at non 2^n F_CPU
2727
.equ FRACT_MAX, (1000 >> 2)
2828
GLABEL TIMER0_OVF_vect
29+
sei ; allow other interrupts
2930
push r16
3031
in r16, SREG
3132
push r16
@@ -34,14 +35,28 @@ GLABEL TIMER0_OVF_vect
3435
push ZH
3536
ldi ZH, hi8(t0_fract)
3637
ld r16, Z
37-
subi r16, lo8(-(FRACT_INC)) ; add millis fraction
38-
cpi r16, FRACT_MAX ; C set when fract < FRACT_MAX
38+
//subi r16, lo8(-(FRACT_INC)) ; add millis fraction
39+
//cpi r16, FRACT_MAX ; C set when fract < FRACT_MAX
40+
subi r16, lo8(FRACT_INC) ; subtract millis fraction
41+
brcc _no_underflow
42+
subi r16, lo8(-FRACT_MAX) ; add FRACT_MAX, clears Carry
43+
rjmp 2f
44+
_no_underflow:
45+
sec ; invert Carry
46+
2:
3947
st Z+, r16
40-
_inc_millis:
48+
; add one more to millis LSB when fractional counter underflows
4149
ld r16, Z
42-
sbci r16, lo8(-(MILLIS_INC +1)) ; r16 += MILLIS_INC + NOT Carry
50+
sbci r16, lo8(-(MILLIS_INC + 1)) ; r16 += MILLIS_INC + NOT Carry
51+
;adc r16, r1 ; r16 += Carry
52+
;sbci r16, lo8(-(MILLIS_INC)) ; r16 += MILLIS_INC
53+
rjmp _save
54+
_add1: ; handle most significant bytes
55+
ld r16, Z
56+
subi r16, -1 ; add 1
57+
_save:
4358
st Z+, r16
44-
brcc _inc_millis
59+
brcc _add1
4560
pop ZH
4661
pop ZL
4762
pop r16

0 commit comments

Comments
 (0)