Skip to content

Commit d87623a

Browse files
committed
v0.5 with timer-based delay
1 parent 9374d5b commit d87623a

File tree

6 files changed

+88
-26
lines changed

6 files changed

+88
-26
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# ArduinoShrink
2-
This library replaces Arduino AVR Core functions with smaller and faster versions.
3-
For example, the Blink example sketch built for the Uno takes 924 bytes of flash, but only needs 196 bytes with ArduinoShrink.
2+
This library replaces Arduino AVR Core functions with smaller and faster versions, with the same functionality.
3+
For example, the Blink example sketch built for the Uno takes 924 bytes of flash, but only needs 286 bytes with ArduinoShrink.
44

55
## Usage
66
Download [a release](https://github.com/nerdralph/ArduinoShrink/releases), and extract the files into your Arduino/libraries folder. Select ArduinoShrink from the Sketch, Include Library menu. This will replace several Arduino functions with smaller and faster versions. The Arduino pin number must be known at compile time if you are using this library.

src/ArduinoShrink.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,18 @@ inline void delayMicroseconds(unsigned int us)
1212
_delay_us(us);
1313
}
1414

15+
// move millis to millis.c - LTO can inline
16+
// millis_raw is slow by 2.4% (1000/1024), so multiply by 1.024
17+
// shift and add instead of multiply: 1 6/256 = 1.0234375
18+
// ifdef RAW_MILLIS - else precise millis
1519
extern "C" uint32_t millis_raw();
1620
inline uint32_t millis()
1721
{
1822
uint32_t m = millis_raw();
19-
return m + ((m * 1573) >> 16);
23+
// return m;
24+
// high-precision millis correction =~ 32 extra bytes
25+
// 1 + 1573/2^16 = 1.0240
26+
// return m + ((m * 1573) >> 16);
27+
return m + m>>6 + m>>7;
2028
}
29+

src/delay.S

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
; (c) Ralph Doncaster 2020
2+
; ArduinoShrink
3+
4+
; all used io registers are < 0x3F
5+
#define __SFR_OFFSET 0
6+
#include <avr/io.h>
7+
#include "macros.inc"
8+
9+
;struct {
10+
; uint32_t t0_ovfl;
11+
; uint8_t ovfl_pad;
12+
;} t0_millis;
13+
14+
15+
; to force t0_isr to get linked in
16+
.global t0_ovfl_isr
17+
18+
; read lower 16 bits of extended TCNT0 into r19:r18
19+
r18_t0cnt:
20+
in r18, TCNT0
21+
lds r19, t0_millis
22+
in r0, TCNT0
23+
sub r0, r18 ; TCNT0 overflow?
24+
brcs r18_t0cnt
25+
ret
26+
27+
; delay for r27:r24 (ulong) ms
28+
GLABEL delay_impl
29+
rcall r18_t0cnt
30+
movw r20, r18 ; r20 = start count
31+
rjmp decms
32+
dloop:
33+
rcall r18_t0cnt
34+
sub r18, r20 ; current - start
35+
sbc r19, r21
36+
subi r18, lo8(T0CNT_PER_MS) ; > 1ms?
37+
sbci r19, hi8(T0CNT_PER_MS)
38+
brcc dloop
39+
subi r20, lo8(-(T0CNT_PER_MS)) ; add 1ms to start
40+
sbci r21, hi8(-(T0CNT_PER_MS))
41+
decms: ; decrement ms argument
42+
sbiw r24, 1
43+
sbci r26, 0
44+
sbci r27, 0
45+
brcc dloop
46+
ret
47+

src/millis.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,20 @@ extern uint32_t micros_raw();
1212
uint32_t micros()
1313
{
1414
register uint32_t u asm("r22");
15-
asm ("%~call %x1" : "=r" (u) : "i"(micros_raw) : "r30", "r31" );
16-
return u * 4;
15+
//asm ("%~call %x1" : "=r" (u) : "i"(micros_raw) : "r30", "r31" );
16+
//return u * 4;
17+
asm (
18+
"%~call %x1 \n"
19+
"ldi r30, lo8(T0_SCALE + 2) \n"
20+
"rcall lsl4_r22_r30 \n"
21+
: "=r" (u) : "i"(micros_raw) : "r30", "r31"
22+
);
23+
return u;
1724
}
1825

26+
// avr-libc math.h does not declare gcc log2 builtin
27+
double log2(double);
28+
1929
// portability macros for mega8
2030
#ifndef TCCR0B
2131
#define TCCR0B TCCR0
@@ -25,6 +35,9 @@ uint32_t micros()
2535
__attribute(( section(".init8"), used, naked))
2636
void init_millis()
2737
{
38+
// scaling factor for t0 vs 16Mhz
39+
uint8_t t0_scale = log2(16000000/F_CPU);
40+
asm ( ".equ T0_SCALE, %0\n" :: "M" (t0_scale) );
2841
TCCR0B = _BV(CS01) | _BV(CS00); // div64 prescaler
2942
TIMSK0 = _BV(TOIE0); // enable overflow interrupt
3043
}

src/wiring.c

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,19 @@
44
#include <Arduino.h>
55
#include <util/delay.h>
66

7-
/*
8-
__attribute ((noinline))
9-
void delay(unsigned long ms)
7+
// lightweight custom function call abi
8+
extern void delay_impl();
9+
void delay(uint32_t msec)
1010
{
11-
do {
12-
_delay_us(999); // leave 1us for loop overhead
13-
} while (--ms);
14-
}
15-
*/
16-
17-
void delay(unsigned long ms)
18-
{
19-
// lower 16-bits of micros is enough considering wraparound
20-
uint16_t start = micros();
21-
22-
while (ms > 0) {
23-
yield();
24-
while (ms > 0 && ((uint16_t)micros() - start) >= 1000) {
25-
ms --;
26-
start += 1000;
27-
}
28-
}
11+
register uint32_t ms asm ("r24") = msec;
12+
asm volatile (
13+
".global T0CNT_PER_MS\n"
14+
".equ T0CNT_PER_MS, 250\n"
15+
"rcall %x1\n"
16+
: "+r"(ms)
17+
: "i"(delay_impl)
18+
: "r18", "r19", "r20", "r21"
19+
);
2920
}
3021

3122
// avr-libc math.h does not declare gcc log2 builtin
@@ -39,3 +30,4 @@ void init()
3930
uint8_t prescaler = log2(F_CPU/500000);
4031
ADCSRA = prescaler | (1 << ADEN);
4132
}
33+

src/wiring_digital.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ inline ioreg_p pin_to_pinreg(uint8_t pin)
2626
inline uint8_t pin_to_bit(uint8_t pin)
2727
{
2828
return digital_pin_to_bit_mask_PGM[pin];
29+
//return ((const __flash uint8_t*) digital_pin_to_bit_mask_PGM)[pin];
2930
}
3031

3132
void pinMode(uint8_t pin, uint8_t mode)

0 commit comments

Comments
 (0)