Skip to content

Commit 1b8f3f6

Browse files
committed
new millis ISR equivalent to Arduno
1 parent 481fd37 commit 1b8f3f6

File tree

2 files changed

+61
-28
lines changed

2 files changed

+61
-28
lines changed

src/t0_ovfl_isr.S

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,51 @@
11
; (c) Ralph Doncaster 2020
22
; ArduinoShrink
33

4+
#define __SFR_OFFSET 0
45
#include <avr/io.h>
56
#include "macros.inc"
67

8+
; millis_pad keeps t0_millis overflow from corrupting memory
79
;struct {
8-
; uint32_t t0_ovfl;
9-
; uint8_t ovfl_pad;
10+
; uint8_t t0_fract;
11+
; uint32_t t0_millis;
12+
; uint8_t millis_pad;
1013
;} t0_millis;
14+
.lcomm t0_fract, 1
15+
.global t0_millis
16+
.lcomm t0_millis, 5 ; t0_millis + pad
17+
18+
; ensure BSS gets cleared
19+
.global __do_clear_bss
1120

1221
; to help with linking
1322
GLABEL t0_ovfl_isr
1423

24+
; this is an optimized asm version of the Arduino core timer overflow
25+
; 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
27+
.equ FRACT_MAX, (1000 >> 2)
1528
GLABEL TIMER0_OVF_vect
1629
push r16
17-
in r16, SREG-0x20
30+
in r16, SREG
1831
push r16
1932
push ZL
20-
ldi ZL, lo8(t0_millis)
33+
ldi ZL, lo8(t0_fract)
2134
push ZH
22-
ldi ZH, hi8(t0_millis)
23-
t0_ovfl_inc:
35+
ldi ZH, hi8(t0_fract)
36+
ld r16, Z
37+
subi r16, lo8(-(FRACT_INC)) ; add millis fraction
38+
cpi r16, FRACT_MAX ; C set when fract < FRACT_MAX
39+
st Z+, r16
40+
_inc_millis:
2441
ld r16, Z
25-
subi r16, -1
42+
sbci r16, lo8(-(MILLIS_INC +1)) ; r16 += MILLIS_INC + NOT Carry
2643
st Z+, r16
27-
brcc t0_ovfl_inc
44+
brcc _inc_millis
2845
pop ZH
2946
pop ZL
3047
pop r16
31-
out SREG-0x20, r16
48+
out SREG, r16
3249
pop r16
3350
reti
3451

src/wiring.c

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,49 @@
33

44
#include <Arduino.h>
55
#include <util/delay.h>
6+
#include "as_common.h"
67

7-
// lightweight custom function call abi
8-
extern void delay_impl();
9-
void delay(uint32_t msec)
8+
// delays a specified number of microseconds - modified from picoCore
9+
// works for clock frequencies of 4Mhz and up
10+
void delayMicroseconds(uint16_t us)
1011
{
11-
register uint32_t ms asm ("r24") = msec;
12-
asm ( ".equ T0CNT_PER_MS, %0\n"
13-
".global T0CNT_PER_MS\n"
14-
// T0 prescaler is 64
15-
:: "i" (F_CPU / 1000 / 64) );
16-
asm volatile (
17-
"rcall %x1\n"
18-
: "+r"(ms)
19-
: "i"(delay_impl)
20-
: "r18", "r19", "r20", "r21"
21-
);
22-
}
12+
// if us is a compile-time constant result is accurate to 1 cycle
13+
if (__builtin_constant_p(us)) {
14+
_delay_us(us);
15+
return;
16+
}
2317

24-
// avr-libc math.h does not declare gcc log2 builtin
25-
double log2(double);
18+
// code below runs when us is not known at compile time
19+
// uses inline asm to guarantee exact cycle counts
20+
const float fMHz = (F_CPU/1000000.0);
21+
delay1us:
22+
// delay 1us per loop, less 4 cycles for overhead
23+
_delay_us(1.0 - (4.0 / fMHz));
24+
asm volatile ("sbiw %[us], 1" : [us]"+d"(us));
25+
asm goto( "brne %l[delay1us]" :::: delay1us);
26+
}
2627

27-
void init()
28+
void init(void)
2829
{
29-
asm("sei");
30+
// T0CNT_PER_MS needed for delay_impl
31+
asm ( ".equ T0CNT_PER_MS, %0\n"
32+
".global T0CNT_PER_MS\n"
33+
:: "i" (F_CPU / 1000 / T0_PRESCALE) );
3034

3135
// setup ADC with 250-500kHz clock
3236
uint8_t prescaler = log2(F_CPU/500000);
3337
ADCSRA = prescaler | (1 << ADEN);
38+
39+
TCCR0B = _BV(CS01) | _BV(CS00); // enable T0, div64 prescale
40+
41+
asm("sei"); // enable interrupts
42+
}
43+
44+
// replace main() from Arduino core
45+
int main(void)
46+
{
47+
init();
48+
setup();
49+
while(1) loop();
3450
}
3551

0 commit comments

Comments
 (0)