From a2b3da769888555fcf5e591bae44f3239618a16c Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Tue, 12 May 2009 10:55:26 +0000 Subject: [PATCH] Optimizing the timer0 overflow handler (for millis()), based on work by WestFW and help from mikalhart. Increasing precision of math constants. --- hardware/cores/arduino/wiring.c | 41 +++++++++++++++++++++++++-------- hardware/cores/arduino/wiring.h | 10 ++++---- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/hardware/cores/arduino/wiring.c b/hardware/cores/arduino/wiring.c index 73c26f211..72bc28221 100755 --- a/hardware/cores/arduino/wiring.c +++ b/hardware/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/hardware/cores/arduino/wiring.h b/hardware/cores/arduino/wiring.h index 9600a0f8e..2f84f78ec 100755 --- a/hardware/cores/arduino/wiring.h +++ b/hardware/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