diff options
author | David A. Mellis <d.mellis@arduino.cc> | 2009-05-12 10:55:26 +0000 |
---|---|---|
committer | David A. Mellis <d.mellis@arduino.cc> | 2009-05-12 10:55:26 +0000 |
commit | 888f15f2a62d2a55ee53eed77fbf5984f6cfffc4 (patch) | |
tree | b7b27e3f60b4d6a384bbdc61386cd2cf2614d4e8 | |
parent | 33fd8b8631bd8d5cd609935a2dd2fbb31688f2c1 (diff) |
Optimizing the timer0 overflow handler (for millis()), based on work by WestFW and help from mikalhart. Increasing precision of math constants.
-rwxr-xr-x | cores/arduino/wiring.c | 41 | ||||
-rwxr-xr-x | cores/arduino/wiring.h | 10 |
2 files changed, 36 insertions, 15 deletions
diff --git a/cores/arduino/wiring.c b/cores/arduino/wiring.c index 73c26f2..72bc282 100755 --- a/cores/arduino/wiring.c +++ b/cores/arduino/wiring.c @@ -24,32 +24,53 @@ #include "wiring_private.h" +// the prescaler is set so that timer0 ticks every 64 clock cycles, and the +// the overflow handler is called every 256 ticks. +#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256)) + +// the whole number of milliseconds per timer0 overflow +#define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000) + +// the fractional number of milliseconds per timer0 overflow. we shift right +// by three to fit these numbers into a byte. (for the clock speeds we care +// about - 8 and 16 MHz - this doesn't lose precision.) +#define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3) +#define FRACT_MAX (1000 >> 3) + volatile unsigned long timer0_overflow_count = 0; -volatile unsigned long timer0_clock_cycles = 0; volatile unsigned long timer0_millis = 0; +static unsigned char timer0_fract = 0; SIGNAL(TIMER0_OVF_vect) { - timer0_overflow_count++; - // timer 0 prescale factor is 64 and the timer overflows at 256 - timer0_clock_cycles += 64UL * 256UL; - while (timer0_clock_cycles > clockCyclesPerMicrosecond() * 1000UL) { - timer0_clock_cycles -= clockCyclesPerMicrosecond() * 1000UL; - timer0_millis++; + // copy these to local variables so they can be stored in registers + // (volatile variables must be read from memory on every access) + unsigned long m = timer0_millis; + unsigned char f = timer0_fract; + + m += MILLIS_INC; + f += FRACT_INC; + if (f >= FRACT_MAX) { + f -= FRACT_MAX; + m += 1; } + + timer0_fract = f; + timer0_millis = m; + timer0_overflow_count++; } unsigned long millis() { unsigned long m; uint8_t oldSREG = SREG; - + // disable interrupts while we read timer0_millis or we might get an - // inconsistent value (e.g. in the middle of the timer0_millis++) + // inconsistent value (e.g. in the middle of a write to timer0_millis) cli(); m = timer0_millis; SREG = oldSREG; - + return m; } diff --git a/cores/arduino/wiring.h b/cores/arduino/wiring.h index 9600a0f..2f84f78 100755 --- a/cores/arduino/wiring.h +++ b/cores/arduino/wiring.h @@ -41,11 +41,11 @@ extern "C"{ #define true 0x1 #define false 0x0 -#define PI 3.14159265 -#define HALF_PI 1.57079 -#define TWO_PI 6.283185 -#define DEG_TO_RAD 0.01745329 -#define RAD_TO_DEG 57.2957786 +#define PI 3.1415926535897932384626433832795 +#define HALF_PI 1.5707963267948966192313216916398 +#define TWO_PI 6.283185307179586476925286766559 +#define DEG_TO_RAD 0.017453292519943295769236907684886 +#define RAD_TO_DEG 57.295779513082320876798154814105 #define SERIAL 0x0 #define DISPLAY 0x1 |