forked from pichenettes/avril
-
Notifications
You must be signed in to change notification settings - Fork 0
/
time.h
executable file
·86 lines (71 loc) · 3.17 KB
/
time.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
// Copyright 2009 Olivier Gillet.
//
// Author: Olivier Gillet ([email protected])
//
// 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 <http://www.gnu.org/licenses/>.
//
// -----------------------------------------------------------------------------
//
// Real time clock.
#ifndef AVRLIB_TIME_H_
#define AVRLIB_TIME_H_
#include <avr/delay.h>
#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_