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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
//! `embassy-time` driver over the BCM System Timer.
//!
//! The System Timer is a free-running 64-bit counter at a fixed 1MHz, so
//! it maps onto `embassy-time`'s tick rate with no scaling at all — the
//! crate pins `tick-hz-1_000_000` for exactly that reason. Deadlines come
//! from its Compare 1 register, the one of C0-C3 not spoken for by the
//! GPU firmware or left free.
//!
//! The ARM generic timer has the better deadline primitives (per-core,
//! 64-bit compare) but is the wrong choice for a *global* timebase: at
//! 19.2MHz it matches no `tick-hz-*` rate `embassy-time` offers, so it
//! would need lossy scaling inside
//! [`Driver::now`](embassy_time_driver::Driver::now), the hottest function
//! on the path.
//!
//! # Wiring
//!
//! Three things have to happen before an `await` on a deadline resolves,
//! and only the first belongs to this crate:
//!
//! 1. [`init`](crate::time_driver::init) takes ownership of Compare 1 and
//! enables its interrupt at the interrupt controller.
//! 2. The application unmasks interrupts at the CPU (`rpi_hal::irq`).
//! 3. The application's `__irq_handler` calls
//! [`on_timer_irq`](crate::time_driver::on_timer_irq) when
//! `Lic::is_timer1_pending` reports this source.
//!
//! Step 3 is the application's because `rpi-hal` leaves `__irq_handler`
//! to it — a library crate cannot define that symbol without taking the
//! whole vector away from the program that owns it.
//!
//! [`Driver::now`](embassy_time_driver::Driver::now) is deliberately usable
//! before any of that: the counter runs from boot with no configuration,
//! which is what lets this driver satisfy `embassy-time`'s requirement that
//! `now()` never fail even if the hardware has not been initialized.
//!
//! (The explicit link targets above are load-bearing: these module docs
//! are merged with the outer doc comment on `pub mod time_driver` in
//! lib.rs, and the merged text resolves intra-doc links in *that* scope --
//! the crate root -- where this module's own items are not in scope. Bare
//! `[`init`]`-style links work in item docs here, just not at module
//! level.)
use RefCell;
use Waker;
use ;
use Driver;
use Queue;
use Lic;
use SYSTMR;
use Timer;
time_driver_impl!;
/// Hands the System Timer's Compare 1 to the `embassy-time` driver and
/// enables its interrupt at the interrupt controller.
///
/// Consuming `timer` is how the application gives up Compare 1: from here
/// on the driver arms and acknowledges it, and a second owner racing it
/// would lose deadlines. That transfer is a statement of intent rather
/// than something the type system enforces, since the PAC allows a
/// peripheral handle to be stolen from anywhere — but an application that
/// keeps no `Timer` cannot reach Compare 1 by accident.
///
/// `lic` is only borrowed: the application still needs it for its own
/// interrupt sources.
///
/// Two steps remain afterwards, both the application's (see the module
/// documentation): unmask interrupts at the CPU, and route this source to
/// [`on_timer_irq`] from `__irq_handler`. Until they are done, deadlines
/// never fire — though `embassy_time::Instant::now()` already reads
/// correctly, before and after this call.
/// Services a System Timer Compare 1 interrupt: wakes every task whose
/// deadline has passed, and arms the next one.
///
/// Call this from the application's `__irq_handler` when
/// `Lic::is_timer1_pending` reports this source. It acknowledges the
/// match itself, so the caller must not also clear it.
///
/// Harmless to call spuriously — with nothing due it simply re-arms —
/// which is what makes the early wake-ups from a clamped far-future
/// deadline a non-event.