Skip to main content

arm_generic_timer/
lib.rs

1// SPDX-FileCopyrightText: Copyright The arm-generic-timer Contributors.
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4#![no_std]
5#![doc = include_str!("../README.md")]
6#![deny(clippy::undocumented_unsafe_blocks)]
7#![deny(unsafe_op_in_unsafe_fn)]
8#![cfg_attr(docsrs, feature(doc_cfg))]
9
10#[cfg(feature = "embedded-hal")]
11mod embedded_hal;
12#[cfg(feature = "embedded-hal-timer")]
13mod embedded_hal_timer;
14pub mod memory_mapped;
15#[cfg(any(test, feature = "fakes", target_arch = "aarch64"))]
16pub mod sysreg;
17mod util;
18
19use core::{hint::spin_loop, time::Duration};
20
21/// Interface for accessing common timer registers.
22pub trait TimerInterface {
23    /// Enables timer
24    fn enable(&mut self);
25
26    /// Returns the frequency in Hz.
27    fn frequency(&self) -> u32;
28
29    /// Returns the down-counter value.
30    fn timer_value(&self) -> i32;
31
32    /// Returns the compare value.
33    fn compare_value(&self) -> u64;
34
35    /// Sets timer value. This programs the compare value relative to the physical counter, which
36    /// affects the value returned by [`TimerInterface::compare_value()`].
37    /// Setting a negative value will trigger an interrupt, if enabled.
38    fn set_timer_value(&mut self, timer_value: i32);
39
40    /// Sets the compare value. This also affects the down-counter value queried using
41    /// [`TimerInterface::timer_value()`].
42    fn set_compare_value(&mut self, compare_value: u64);
43
44    /// Unmasks / masks interrupts for the counter.
45    fn enable_interrupt(&mut self, enabled: bool);
46}
47
48/// Generic timer object allowing blocking wait and interrupt enablement.
49pub struct Timer<T: TimerInterface> {
50    timer: T,
51}
52
53impl<T: TimerInterface> Timer<T> {
54    /// Creates new instance.
55    pub fn new(timer: T) -> Self {
56        Self { timer }
57    }
58
59    /// Enables timer.
60    pub fn enable(&mut self) {
61        self.timer.enable();
62    }
63
64    /// Blocking waits for a duration or maximal possible timer. The timer must be enabled before
65    /// calling wait.
66    pub fn wait(&self, duration: Duration) {
67        let ticks = util::duration_to_ticks(duration, self.timer.frequency());
68        let increment = u32::try_from(ticks).unwrap_or(u32::MAX);
69
70        let start = self.timer.timer_value();
71
72        // The timer is a down-counter
73        while (start.wrapping_sub(self.timer.timer_value()) as u32) < increment {
74            spin_loop();
75        }
76    }
77
78    /// Returns the downcounter value as a duration.
79    pub fn remaining_time(&self) -> Duration {
80        util::ticks_to_duration(
81            u64::try_from(self.timer.timer_value()).unwrap_or(0),
82            self.timer.frequency(),
83        )
84    }
85
86    /// Sets the remaining timer duration.
87    ///
88    /// If the duration converted to ticks overflows `i32`, TVAL will be set to `i32::MAX` ticks.
89    pub fn set_remaining_time(&mut self, duration: Duration) {
90        let ticks = i32::try_from(util::duration_to_ticks(duration, self.timer.frequency()))
91            .unwrap_or(i32::MAX);
92
93        self.timer.set_timer_value(ticks);
94    }
95
96    /// Unmasks interrupts for this timer.
97    /// Interrupts and output signals will only be emitted if [`Self::enable()`] has been called.
98    pub fn enable_interrupt(&mut self) {
99        self.timer.enable_interrupt(true);
100    }
101
102    /// Masks interrupts for this timer.
103    pub fn disable_interrupt(&mut self) {
104        self.timer.enable_interrupt(false);
105    }
106}
107
108/// Interface for accessing common counter registers.
109pub trait CounterInterface {
110    /// Returns the up-counter value.
111    fn counter_value(&self) -> u64;
112
113    /// Returns the counter frequency in Hz.
114    fn frequency(&self) -> u32;
115}
116
117/// An up-counter keeping track of elapsed time.
118pub struct Counter<C: CounterInterface> {
119    counter: C,
120    offset: u64,
121}
122
123impl<C: CounterInterface> Counter<C> {
124    /// Creates a new instance.
125    pub fn new(counter: C) -> Self {
126        Self { counter, offset: 0 }
127    }
128
129    /// Returns the counter value in ticks.
130    fn counter_value(&self) -> u64 {
131        self.counter.counter_value() - self.offset
132    }
133
134    /// Returns the counter value.
135    pub fn elapsed_time(&self) -> Duration {
136        util::ticks_to_duration(self.counter_value(), self.counter.frequency())
137    }
138}
139
140#[cfg(test)]
141mod tests {
142    use super::*;
143    use core::cell::Cell;
144
145    /// Mock timer for use in unit tests.
146    ///
147    /// Queries of `timer_value` are based on `counter_values` and `compare_value`. On every query,
148    /// the next available `counter_value` is used, until the list is exhausted.
149    struct MockTimer<'a> {
150        enabled: bool,
151        frequency: u32,
152        counter_values: &'a [u64],
153        compare_value: u64,
154        value_index: Cell<usize>,
155    }
156
157    impl<'a> MockTimer<'a> {
158        /// Value representing an arbitrary `i32` returned by querying `TVAL` when the timer is not
159        /// enabled.
160        pub const UNKNOWN_TVAL: i32 = 0x1234_BCDE;
161
162        /// Creates a new mock timer. `counter_values` are the mock values for physical counts.
163        pub fn new(frequency: u32, counter_values: &'a [u64], compare_value: u64) -> Self {
164            Self {
165                enabled: false,
166                frequency,
167                counter_values,
168                compare_value,
169                value_index: Cell::new(0),
170            }
171        }
172
173        fn next_counter_value(&self) -> u64 {
174            let index = self.value_index.get();
175            self.value_index.update(|i| i + 1);
176
177            *self
178                .counter_values
179                .get(index)
180                .expect("Mock counter query out of bounds")
181        }
182    }
183
184    impl<'a> Drop for MockTimer<'a> {
185        fn drop(&mut self) {
186            assert!(
187                self.counter_values.len() <= self.value_index.get(),
188                "Not all timer values have been used: {:?}",
189                &self.counter_values[self.value_index.get()..]
190            );
191        }
192    }
193
194    impl<'a> TimerInterface for MockTimer<'a> {
195        fn enable(&mut self) {
196            self.enabled = true;
197        }
198
199        fn frequency(&self) -> u32 {
200            self.frequency
201        }
202
203        fn timer_value(&self) -> i32 {
204            if !self.enabled {
205                return Self::UNKNOWN_TVAL;
206            }
207
208            let cval = self.compare_value;
209            let physical_count = self.next_counter_value();
210
211            // intentionally truncated to 32 bits:
212            // TimerValue is the low 32 bits of `ZeroExtend{64}((CVAL - PhysicalCountInt)[31:0])`
213            cval.wrapping_sub(physical_count) as i32
214        }
215
216        fn compare_value(&self) -> u64 {
217            self.compare_value
218        }
219
220        fn set_timer_value(&mut self, timer_value: i32) {
221            self.compare_value = self
222                .counter_values
223                .get(self.value_index.get())
224                .unwrap()
225                .wrapping_add(timer_value as u64);
226        }
227
228        fn set_compare_value(&mut self, compare_value: u64) {
229            self.compare_value = compare_value
230        }
231
232        fn enable_interrupt(&mut self, _enabled: bool) {
233            unimplemented!()
234        }
235    }
236
237    #[test]
238    fn wait() {
239        let mock = MockTimer::new(1000, &[0, 2000, 4000, 5000], 0);
240
241        let mut timer = Timer::new(mock);
242        timer.enable();
243
244        timer.wait(Duration::from_secs(5));
245    }
246
247    #[test]
248    fn wait_overflow() {
249        let mock = MockTimer::new(1000, &[1, 1000, 0], 0);
250
251        let mut timer = Timer::new(mock);
252        timer.enable();
253        timer.wait(Duration::from_secs(u64::MAX));
254    }
255
256    #[test]
257    fn set_remaining_time() {
258        let mock = MockTimer::new(1000, &[5000], 0);
259        let mut timer = Timer::new(mock);
260        timer.enable();
261
262        timer.set_remaining_time(Duration::from_secs(2));
263        assert_eq!(timer.timer.compare_value(), 7000);
264
265        assert_eq!(timer.remaining_time(), Duration::from_secs(2));
266    }
267
268    #[test]
269    fn remaining_time_cval() {
270        let mock = MockTimer::new(1000, &[1000, 2000], 3000);
271        let mut timer = Timer::new(mock);
272        timer.enable();
273
274        assert_eq!(timer.remaining_time(), Duration::from_secs(2));
275        assert_eq!(timer.remaining_time(), Duration::from_secs(1));
276    }
277
278    #[test]
279    fn disabled_timer() {
280        let mock = MockTimer::new(1, &[], 0);
281        let timer = Timer::new(mock);
282
283        assert_eq!(
284            timer.remaining_time(),
285            Duration::from_secs(MockTimer::UNKNOWN_TVAL as u64)
286        );
287    }
288
289    #[test]
290    fn remaining_time() {
291        let compare_value = u32::MAX as u64;
292        let counter_values = [
293            compare_value - i32::MAX.unsigned_abs() as u64,
294            compare_value - 1000,
295            compare_value,
296            compare_value + i32::MIN.unsigned_abs() as u64,
297            compare_value + 1,
298        ];
299        let mock = MockTimer::new(1, &counter_values, compare_value);
300        let mut timer = Timer::new(mock);
301        timer.enable();
302
303        // TVAL = i32::MAX
304        assert_eq!(timer.remaining_time(), Duration::from_secs(i32::MAX as u64));
305
306        // TVAL = 1000
307        assert_eq!(timer.remaining_time(), Duration::from_secs(1000));
308
309        // TVAL = 0
310        assert_eq!(timer.remaining_time(), Duration::from_secs(0));
311
312        // TVAL = i32::MIN
313        assert_eq!(timer.remaining_time(), Duration::from_secs(0));
314
315        // TVAL = -1
316        assert_eq!(timer.remaining_time(), Duration::from_secs(0));
317    }
318
319    #[test]
320    fn wait_negative() {
321        let counter_values = [0, i32::MIN.unsigned_abs() as u64];
322        let mock = MockTimer::new(1, &counter_values, 0);
323        let mut timer = Timer::new(mock);
324        timer.enable();
325
326        // wait() will take the "current" timer value, 0 as the start time
327        // It will then consume i32::MIN from the MockTimer, after i32::MIN seconds.
328        let wait_duration = -(i32::MIN as i64) as u64;
329
330        timer.wait(Duration::from_secs(wait_duration));
331    }
332
333    #[test]
334    fn wait_around_zero() {
335        let mock = MockTimer::new(1, &[0, 1, 2, 3], 1);
336        let mut timer = Timer::new(mock);
337        timer.enable();
338
339        timer.wait(Duration::from_secs(3));
340    }
341
342    #[test]
343    fn wait_extremities() {
344        let compare_value = i32::MAX as u64;
345        let counter_values = [
346            0,
347            compare_value,
348            compare_value + i32::MIN.unsigned_abs() as u64,
349        ];
350        let mock = MockTimer::new(1, &counter_values, compare_value);
351        let mut timer = Timer::new(mock);
352        timer.enable();
353
354        let wait_duration = u32::MAX as u64 + 1;
355
356        timer.wait(Duration::from_secs(wait_duration));
357    }
358}