// Copyright 2009 Olivier Gillet. // // Author: Olivier Gillet (ol.gillet@gmail.com) // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // ----------------------------------------------------------------------------- // // Real time clock. #ifndef AVRLIB_TIME_H_ #define AVRLIB_TIME_H_ #include #include "avrlib/base.h" namespace avrlib { uint32_t milliseconds(); uint32_t Delay(uint32_t delay); #define ConstantDelay(x) _delay_ms((x)) void InitClock(); const uint32_t microseconds_per_timer0_overflow = (64 * 256) / (F_CPU / 1000000L); const uint32_t milliseconds_increment = microseconds_per_timer0_overflow / 1000; const uint32_t fractional_increment = ( microseconds_per_timer0_overflow % 1000) >> 3; const uint8_t fractional_max = 1000 >> 3; // The timer count is stored as an union instead of a mere uint32_t because we // need access to the individual 16-bit parts of the value. extern volatile LongWord timer0_milliseconds; extern uint8_t timer0_fractional; inline void TickSystemClock() { // Compile-time optimization: with a 20Mhz clock rate, milliseconds_increment // is always null, so we have to increment it only when there's a // fractional overflow! if (milliseconds_increment) { timer0_milliseconds.value += milliseconds_increment; } timer0_fractional += fractional_increment; if (timer0_fractional >= fractional_max) { timer0_fractional -= fractional_max; // The next lines are equivalent to: ++timer0_fractional. Why am I not // using ++timer0_fractional? The reason is in the way gcc compiles this. // 32-bits values are always loaded into contiguous registers. This code is // called from an ISR, so this means 4 contiguous registers are going to // be pushed/popped in the ISR. This costs 4 pairs of push/pops (16 cycles). // On the other hand, this weird implementation only requires 2 adjacent // registers, and they are probably already used for something else in the // ISR. There's no free lunch, though: this code is less efficient than // a++. However, when it is called every 16th or 32th entry in an ISR, the // time saved by avoiding the extra push/pops makes it a better choice. // // Rule: when you *occasionnally* do something complicated from within an // ISR, the code doing the complicated thing should really try to minimize // the number of registers it uses, even if it takes more cycles to do // the work. ++timer0_milliseconds.words[0]; if (timer0_milliseconds.words[0] == 0) { ++timer0_milliseconds.words[1]; } } } } // namespace avrlib #endif // AVRLIB_TIME_H_