Optimizing the timer0 overflow handler (for millis()), based on work by WestFW and help from mikalhart. Increasing precision of math constants.

This commit is contained in:
David A. Mellis 2009-05-12 10:55:26 +00:00
parent 60ad594d7b
commit a2b3da7698
2 changed files with 36 additions and 15 deletions

View File

@ -24,32 +24,53 @@
#include "wiring_private.h" #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_overflow_count = 0;
volatile unsigned long timer0_clock_cycles = 0;
volatile unsigned long timer0_millis = 0; volatile unsigned long timer0_millis = 0;
static unsigned char timer0_fract = 0;
SIGNAL(TIMER0_OVF_vect) SIGNAL(TIMER0_OVF_vect)
{ {
timer0_overflow_count++; // copy these to local variables so they can be stored in registers
// timer 0 prescale factor is 64 and the timer overflows at 256 // (volatile variables must be read from memory on every access)
timer0_clock_cycles += 64UL * 256UL; unsigned long m = timer0_millis;
while (timer0_clock_cycles > clockCyclesPerMicrosecond() * 1000UL) { unsigned char f = timer0_fract;
timer0_clock_cycles -= clockCyclesPerMicrosecond() * 1000UL;
timer0_millis++; 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 millis()
{ {
unsigned long m; unsigned long m;
uint8_t oldSREG = SREG; uint8_t oldSREG = SREG;
// disable interrupts while we read timer0_millis or we might get an // 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(); cli();
m = timer0_millis; m = timer0_millis;
SREG = oldSREG; SREG = oldSREG;
return m; return m;
} }

View File

@ -41,11 +41,11 @@ extern "C"{
#define true 0x1 #define true 0x1
#define false 0x0 #define false 0x0
#define PI 3.14159265 #define PI 3.1415926535897932384626433832795
#define HALF_PI 1.57079 #define HALF_PI 1.5707963267948966192313216916398
#define TWO_PI 6.283185 #define TWO_PI 6.283185307179586476925286766559
#define DEG_TO_RAD 0.01745329 #define DEG_TO_RAD 0.017453292519943295769236907684886
#define RAD_TO_DEG 57.2957786 #define RAD_TO_DEG 57.295779513082320876798154814105
#define SERIAL 0x0 #define SERIAL 0x0
#define DISPLAY 0x1 #define DISPLAY 0x1