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
9/// Memory mapped timer driver implementations.
10///
11/// See I5.6 Generic Timer memory-mapped registers overview.
12pub mod memory_mapped;
13/// System register based timer driver implementations.
14///
15/// See D24.10 Generic Timer registers.
16#[cfg(any(test, feature = "fakes", target_arch = "aarch64"))]
17pub mod sysreg;
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) -> u32;
31}
32
33/// Generic timer object allowing blocking wait and interrupt enablement.
34pub struct Timer<T: TimerInterface> {
35    timer: T,
36}
37
38impl<T: TimerInterface> Timer<T> {
39    /// Creates new instance.
40    pub fn new(timer: T) -> Self {
41        Self { timer }
42    }
43
44    /// Enables timer.
45    pub fn enable(&mut self) {
46        self.timer.enable();
47    }
48
49    /// Blocking waits for a duration or maximal possible timer. The timer must be enabled before
50    /// calling wait.
51    pub fn wait(&self, duration: Duration) {
52        let ticks =
53            u128::from(self.timer.frequency()).saturating_mul(duration.as_micros()) / 1_000_000;
54        let increment = u32::try_from(ticks).unwrap_or(u32::MAX);
55
56        let start = self.timer.timer_value();
57
58        // The timer is a down-counter
59        while start.wrapping_sub(self.timer.timer_value()) < increment {
60            spin_loop();
61        }
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68    use core::cell::Cell;
69
70    struct MockTimer<'a> {
71        frequency: u32,
72        timer_values: &'a [u32],
73        value_index: Cell<usize>,
74    }
75
76    impl<'a> MockTimer<'a> {
77        pub fn new(frequency: u32, timer_values: &'a [u32]) -> Self {
78            Self {
79                frequency,
80                timer_values,
81                value_index: Cell::new(0),
82            }
83        }
84    }
85
86    impl<'a> Drop for MockTimer<'a> {
87        fn drop(&mut self) {
88            assert!(
89                self.timer_values.len() == self.value_index.get(),
90                "Not all timer values have been used: {:?}",
91                &self.timer_values[self.value_index.get()..]
92            );
93        }
94    }
95
96    impl<'a> TimerInterface for MockTimer<'a> {
97        fn enable(&mut self) {}
98
99        fn frequency(&self) -> u32 {
100            self.frequency
101        }
102
103        fn timer_value(&self) -> u32 {
104            let index = self.value_index.get();
105            self.value_index.update(|i| i + 1);
106
107            self.timer_values[index]
108        }
109    }
110
111    #[test]
112    fn wait() {
113        let mock = MockTimer::new(1000, &[7000, 5000, 3000, 2000]);
114
115        let timer = Timer::new(mock);
116        timer.wait(Duration::from_secs(5));
117    }
118
119    #[test]
120    fn wait_overflow() {
121        let mock = MockTimer::new(1000, &[2000, 1000, 2001]);
122
123        let timer = Timer::new(mock);
124        timer.wait(Duration::from_secs(u64::MAX));
125    }
126}