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