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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
//! Free-running counter for measuring elapsed time (durations / intervals).
//!
//! This is the *measurement* counterpart to [`crate::delay`]: where `Delay`
//! spends a known number of cycles to make time pass, [`Counter`] reads a
//! hardware counter to find out how much time *has* passed between two points.
//!
//! # How a duration is measured
//!
//! A Timer_A block contains a 16-bit counter, `TAxR`, that increments on every
//! tick of a clock you select. Put it in **continuous mode** and it free-runs:
//! 0, 1, 2, … 0xFFFF, 0, 1, … forever, with no CPU involvement. To time
//! something you snapshot the counter before and after and subtract:
//!
//! ```ignore
//! let start = counter.now();
//! do_the_thing();
//! let elapsed_ticks = counter.now().wrapping_sub(start);
//! let us = counter.ticks_to_us(elapsed_ticks);
//! ```
//!
//! `wrapping_sub` is load-bearing: the counter is modular (16-bit), so as long
//! as the interval is shorter than one full period the subtraction is correct
//! *even when the counter wraps through zero in between*. `60000.wrapping_sub(
//! 65000) == 61072` ticks — exactly the right answer across one rollover.
//! [`Counter::elapsed_since`] wraps this for you.
//!
//! # Resolution vs. range — the one real decision
//!
//! The counter is 16 bits, so it rolls over every 65536 ticks. The tick rate is
//! the selected clock divided by [`Divider`], and that single choice trades
//! timing resolution against the longest interval you can measure before the
//! counter laps itself and the subtraction silently lies:
//!
//! | SMCLK | Divider | Tick rate | Resolution | Wraps after |
//! |-------|---------|-----------|------------|-------------|
//! | 8 MHz | ÷1 | 8 MHz | 125 ns | 8.19 ms |
//! | 8 MHz | ÷8 | 1 MHz | 1 µs | 65.5 ms |
//! | 1 MHz | ÷1 | 1 MHz | 1 µs | 65.5 ms |
//!
//! Out of the box [`now`](Counter::now) measures **single intervals shorter
//! than one wrap period**. To time anything longer, enable the overflow
//! interrupt with [`Counter::enable_overflow_interrupt`] and have the
//! `TIMER0_A1` ISR tally rollovers in a shared counter; then
//! [`Counter::now32`] assembles those tallies with `TAxR` into a 32-bit
//! timestamp (~71 minutes before *it* wraps, at the 1 MHz tick). The ISR, the
//! shared counter, and enabling interrupts globally live in the application —
//! see `hal_test_runners` for a worked example.
//!
//! # Hardware capture
//!
//! A software [`now`](Counter::now) read is taken whenever the CPU reaches the
//! instruction — so interrupt latency and scheduling jitter land *in* the
//! measurement. A capture/compare channel in **capture mode** instead latches
//! `TAxR` into `TAxCCR1` the moment a selected edge arrives, in hardware, so the
//! timestamp reflects the *event* regardless of when software reads it.
//! [`configure_capture`](Counter::configure_capture) sets this up on CCR1, and
//! [`software_capture`](Counter::software_capture) triggers one without any
//! external pin by toggling the internal `CCIS` input GND→VCC. (A true external
//! edge would route a pin to the channel's `CCIxA`/`CCIxB` input instead — on
//! this part `TA0.1`/CCI1A is P1.0, which is the green LED, so the pin route is
//! left as a later exercise.)
//!
//! # The overflow read race
//!
//! Reading a 32-bit timestamp out of a 16-bit counter plus a software high word
//! is not atomic: the counter can roll over (setting `TAIFG`) in the window
//! between sampling the high word and the low word. [`now32`](Counter::now32)
//! must therefore be called inside a critical section (interrupts masked, so the
//! ISR cannot run mid-read) and reconciles a *pending-but-uncounted* overflow
//! itself by checking `TAIFG` — see its docs.
//!
//! # Clock source
//!
//! [`Counter::new_smclk`] sources the counter from **SMCLK**, the same clock the
//! UART's BRCLK runs on. SMCLK is gated off in LPM3, so an SMCLK-sourced counter
//! does *not* run in deep sleep. To measure (and wake) through LPM3, use
//! [`Counter::new_aclk`] instead — ACLK on the 32.768 kHz crystal keeps ticking
//! in LPM3 — and arm [`Counter::schedule_wake_in`] (a CCR0 compare) to fire the
//! `TIMER0_A0` interrupt at a chosen tick. Either way the tick rate is read from
//! [`Clocks`] (single source of truth) exactly as [`crate::delay::Delay`] reads
//! MCLK, so the tick↔time math tracks whichever clock profile you configured.
use crateClocks;
use cratepac;
/// Counter input divider applied to the selected clock (the `ID` field of
/// `TAxCTL`). Lower divisors give finer resolution but a shorter span before the
/// 16-bit counter wraps; see the table in the module docs.
/// A free-running 16-bit up-counter on Timer0_A3, used as a timestamp source.
///
/// Consumes the `Timer0A3` peripheral so the counter is owned and configured in
/// exactly one place. Snapshot it with [`now`](Counter::now); turn a tick delta
/// into real time with [`ticks_to_us`](Counter::ticks_to_us) /
/// [`ticks_to_ns`](Counter::ticks_to_ns).
/// Disarm the CCR0 compare wake from inside the `TIMER0_A0` ISR.
///
/// The dedicated `TIMER0_A0` vector auto-clears CCR0's `CCIFG` on service, so
/// the handler only needs to clear `CCIE` to stop the one-shot from re-firing on
/// the next wrap. Provided as a free function because the ISR does not own the
/// [`Counter`], mirroring [`clear_overflow_irq`].
/// Clear a pending Timer0_A3 overflow interrupt (`TAIFG`).
///
/// Intended to be called from the `TIMER0_A1` ISR, which does not own the
/// [`Counter`]; it clears only `TAIFG`, leaving the source/divider/mode/enable
/// bits intact. The read-modify-write cannot race the hardware re-setting
/// `TAIFG` — the next overflow is a full counter period away.