From e8465fbb4500ed3968e7a06c2d75a5b3f1841b8e Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Fri, 18 Apr 2008 21:56:14 +0000 Subject: Fixing millis() overflow: changing millis() and the timer 0 overflow handler so that the millis count is updated in the interrupt, and so we don't need to do a conversion inside millis(). Updated to do list. --- cores/arduino/wiring.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'cores/arduino') diff --git a/cores/arduino/wiring.c b/cores/arduino/wiring.c index dd07a5f..8459229 100755 --- a/cores/arduino/wiring.c +++ b/cores/arduino/wiring.c @@ -24,26 +24,29 @@ #include "wiring_private.h" -// The number of times timer 0 has overflowed since the program started. -// Must be volatile or gcc will optimize away some uses of it. -volatile unsigned long timer0_overflow_count; +volatile unsigned long timer0_clock_cycles = 0; +volatile unsigned long timer0_millis = 0; SIGNAL(SIG_OVERFLOW0) { - 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++; + } } unsigned long millis() { - // timer 0 increments every 64 cycles, and overflows when it reaches - // 256. we would calculate the total number of clock cycles, then - // divide by the number of clock cycles per millisecond, but this - // overflows too often. - //return timer0_overflow_count * 64UL * 256UL / (F_CPU / 1000UL); + unsigned long m; + uint8_t oldSREG = SREG; - // instead find 1/128th the number of clock cycles and divide by - // 1/128th the number of clock cycles per millisecond - return timer0_overflow_count * 64UL * 2UL / (F_CPU / 128000UL); + cli(); + m = timer0_millis; + SREG = oldSREG; + + return m; } void delay(unsigned long ms) @@ -122,8 +125,6 @@ void init() // work there sei(); - // timer 0 is used for millis() and delay() - timer0_overflow_count = 0; // on the ATmega168, timer 0 is also used for fast hardware pwm // (using phase-correct PWM would mean that timer 0 overflowed half as often // resulting in different millis() behavior on the ATmega8 and ATmega168) -- cgit v1.2.3-18-g5258