-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsystimer.h
148 lines (121 loc) · 3.99 KB
/
systimer.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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Copyright (c) 2020 Jan Brittenson
// See LICENSE for details.
#ifndef _SYSTIMER_H_
#define _SYSTIMER_H_
#include "common.h"
#include "timer.h"
#define TIMER_USEC(U) (uint32_t(U)*SYSTIMER_CLOCK/1000000UL)
#define TIMER_MSEC(M) (uint32_t(M)*SYSTIMER_CLOCK/1000UL)
#define TIMER_SEC(S) (uint32_t(S)*SYSTIMER_CLOCK)
template <typename _BaseTimer>
class SysTimerAB: public _BaseTimer {
public:
typedef _BaseTimer Timer;
class Future {
uint32_t _time;
public:
explicit Future(uint32_t t = 0) // also default ctor
: _time(t) {
}
Future(const Future& f)
: _time(f._time) {
}
Future& operator=(const Future& f) {
if (this != &f) {
_time = f._time;
}
return *this;
}
volatile Future& operator=(const Future& f) volatile {
if (this != &f) {
_time = f._time;
}
return *this;
}
bool operator<(const Future& rhs) const {
return int32_t(_time - rhs._time) < 0;
}
void adjust(int32_t amount) {
_time += amount;
}
uint32_t time() const { return _time; }
uint32_t time() const volatile { return _time; }
};
protected:
friend void SysTimer_ccr0_intr();
volatile static uint32_t _time;
volatile static Future _sleep; // If a task is sleeping, this is its wake time
volatile static void* _sleeper; // If a task is sleeping, this points to it
public:
enum {
MIN_WAIT = 10,
MAX_WAIT = (1UL << 30) - 1, // In SYSTIMER_CLOCKs
CCR = 0, // CCR to use (not that CCR0 has its own vector)
CCR_LIMIT = 0xf800 // Timer interrupt point
};
static void init() {
#ifdef SYSTIMER_SOURCE
Timer::config(Timer::SYSTIMER_SOURCE, Timer::SOURCE_DIV_8);
#else
Timer::config(Timer::SOURCE_ACLK, Timer::SOURCE_DIV_8);
#endif
Timer::start(Timer::MODE_CONT);
Timer::set_counter(CCR, Timer::ENABLE_INTR, CCR_LIMIT);
}
static void delay(uint32_t ticks) {
wait(future(ticks));
}
static void wait(const Future& future) {
while (!due(future))
;
}
static uint32_t ticks() {
NoInterrupt g;
return _time + Timer::TA_R;
}
static Future future(uint32_t t) {
return Future(ticks() + t);
}
// Calculate signed distance between current time and future, treated as a
// sequence with a span of up 2^31 CLOCKs.
static int32_t remainder(const Future& future) {
return int32_t(future.time() - ticks());
}
// True if future is due past due
static bool due(const Future& future) {
return remainder(future) <= 0;
}
// Set sleeper task. Call with interrupts disabled.
static void set_sleeper_task(void* task, const Future& sleep) {
if (task != _sleeper) {
_sleeper = task;
_sleep = (Future&)sleep;
update_ccr();
}
}
// No sleeper task. Call with interrupts disabled.
static void no_sleeper_task() {
_sleeper = NULL;
update_ccr();
}
// Get current sleeper task.
static void* sleeper() { return (void*)_sleeper; }
// Update CCR. Must be called with interrupts disabled.
static void update_ccr() {
if (!_sleeper) {
Timer::set_counter(CCR, Timer::ENABLE_INTR, CCR_LIMIT);
return;
}
const int32_t r = _sleep.time() - _time;
if (r >= CCR_LIMIT) {
Timer::set_counter(CCR, Timer::ENABLE_INTR, CCR_LIMIT);
} else {
const uint16_t r2 = r;
// If it's so close it's practically due, set count slightly ahead of
// the timer register and let the ISR run immediately.
// XXX Set the IFG here instead?
Timer::set_counter(CCR, Timer::ENABLE_INTR, max<uint16_t>(Timer::TA_R + 8, r2));
}
}
};
#endif // _SYSTIMER_H_