You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

87 lines
3.2KB

  1. // Copyright 2009 Olivier Gillet.
  2. //
  3. // Author: Olivier Gillet (ol.gillet@gmail.com)
  4. //
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. //
  16. // -----------------------------------------------------------------------------
  17. //
  18. // Real time clock.
  19. #ifndef AVRLIB_TIME_H_
  20. #define AVRLIB_TIME_H_
  21. #include <avr/delay.h>
  22. #include "avrlib/base.h"
  23. namespace avrlib {
  24. uint32_t milliseconds();
  25. uint32_t Delay(uint32_t delay);
  26. #define ConstantDelay(x) _delay_ms((x))
  27. void InitClock();
  28. const uint32_t microseconds_per_timer0_overflow =
  29. (64 * 256) / (F_CPU / 1000000L);
  30. const uint32_t milliseconds_increment =
  31. microseconds_per_timer0_overflow / 1000;
  32. const uint32_t fractional_increment = (
  33. microseconds_per_timer0_overflow % 1000) >> 3;
  34. const uint8_t fractional_max = 1000 >> 3;
  35. // The timer count is stored as an union instead of a mere uint32_t because we
  36. // need access to the individual 16-bit parts of the value.
  37. extern volatile LongWord timer0_milliseconds;
  38. extern uint8_t timer0_fractional;
  39. inline void TickSystemClock() {
  40. // Compile-time optimization: with a 20Mhz clock rate, milliseconds_increment
  41. // is always null, so we have to increment it only when there's a
  42. // fractional overflow!
  43. if (milliseconds_increment) {
  44. timer0_milliseconds.value += milliseconds_increment;
  45. }
  46. timer0_fractional += fractional_increment;
  47. if (timer0_fractional >= fractional_max) {
  48. timer0_fractional -= fractional_max;
  49. // The next lines are equivalent to: ++timer0_fractional. Why am I not
  50. // using ++timer0_fractional? The reason is in the way gcc compiles this.
  51. // 32-bits values are always loaded into contiguous registers. This code is
  52. // called from an ISR, so this means 4 contiguous registers are going to
  53. // be pushed/popped in the ISR. This costs 4 pairs of push/pops (16 cycles).
  54. // On the other hand, this weird implementation only requires 2 adjacent
  55. // registers, and they are probably already used for something else in the
  56. // ISR. There's no free lunch, though: this code is less efficient than
  57. // a++. However, when it is called every 16th or 32th entry in an ISR, the
  58. // time saved by avoiding the extra push/pops makes it a better choice.
  59. //
  60. // Rule: when you *occasionnally* do something complicated from within an
  61. // ISR, the code doing the complicated thing should really try to minimize
  62. // the number of registers it uses, even if it takes more cycles to do
  63. // the work.
  64. ++timer0_milliseconds.words[0];
  65. if (timer0_milliseconds.words[0] == 0) {
  66. ++timer0_milliseconds.words[1];
  67. }
  68. }
  69. }
  70. } // namespace avrlib
  71. #endif // AVRLIB_TIME_H_