Skip to main content

aarch32_cpu/generic_timer/
mod.rs

1//! Support for Arm Generic Timer
2//!
3//! See Chapter G6: The Generic Timer in AArch32 State in [ARM Architecture
4//! Reference Manual v8][armv8].
5//!
6//! The Generic Timer existed in Armv7-A as well, but not in Armv7-R.
7//!
8//! [armv8]: https://developer.arm.com/documentation/ddi0487/latest/
9
10mod el2;
11pub use el2::{El2HypPhysicalTimer, El2PhysicalTimer, El2VirtualTimer};
12
13mod el1;
14pub use el1::{El1PhysicalTimer, El1VirtualTimer};
15
16mod el0;
17pub use el0::{El0PhysicalTimer, El0VirtualTimer};
18
19/// Describes either a Physical or Virtual timer
20pub trait GenericTimer {
21    /// Get the timer frequency
22    fn frequency_hz(&self) -> u32;
23
24    /// Get the current counter value.
25    ///
26    /// This is a 64-bit value that goes up. It can be used to measure the
27    /// passing of time.
28    ///
29    /// Note that speculative reads are allowed and reads may occur out of
30    /// order. Add ISB and DSB fences before/after this call as required.
31    fn counter(&self) -> u64;
32
33    /// Get the counter compare value.
34    fn counter_compare(&self) -> u64;
35
36    /// Set the counter compare value.
37    ///
38    /// The timer condition is met when the `counter - compare_value >= 0`. This
39    /// therefore operates as a *count-up* timer.
40    fn counter_compare_set(&mut self, value: u64);
41
42    /// Get the current value of the countdown timer.
43    fn countdown(&self) -> u32;
44
45    /// Set the value of the count-down timer.
46    ///
47    /// Sets a value which is decremented on every counter tick. When it reaches
48    /// zero, the timer fires.
49    fn countdown_set(&mut self, duration_ticks: u32);
50
51    /// This is timer enabled?
52    fn enabled(&self) -> bool;
53
54    /// Enable/disable this timer
55    fn enable(&self, enabled: bool);
56
57    /// Is this timer's interrupt masked?
58    fn interrupt_masked(&self) -> bool;
59
60    /// Mask (or unmask) this timer's interrupt.
61    fn interrupt_mask(&mut self, mask: bool);
62
63    /// Has this timer's interrupt fired?
64    fn interrupt_status(&self) -> bool;
65
66    /// Wait for some number of clock ticks
67    fn delay_ticks(&mut self, ticks: u32) {
68        let enabled = self.enabled();
69        self.enable(true);
70        self.countdown_set(ticks);
71        while !self.interrupt_status() {
72            core::hint::spin_loop();
73        }
74        if !enabled {
75            self.enable(false);
76        }
77    }
78
79    /// Delay for some number of milliseconds
80    fn delay_ms(&mut self, ms: u32) {
81        // can't overflow a u64 if you multiply two u32s together
82        let mut ticks: u64 = u64::from(self.frequency_hz()).wrapping_mul(u64::from(ms)) / 1000;
83        while ticks >= 0xFFFF_FFFF {
84            self.delay_ticks(0xFFFF_FFFF);
85            ticks -= 0xFFFF_FFFF;
86        }
87        self.delay_ticks(ticks as u32);
88    }
89
90    /// Delay for some number of microseconds
91    fn delay_us(&mut self, us: u32) {
92        // can't overflow a u64 if you multiply two u32s together
93        let mut ticks: u64 = u64::from(self.frequency_hz()).wrapping_mul(u64::from(us)) / 1_000_000;
94        while ticks >= 0xFFFF_FFFF {
95            self.delay_ticks(0xFFFF_FFFF);
96            ticks -= 0xFFFF_FFFF;
97        }
98        self.delay_ticks(ticks as u32);
99    }
100}
101
102/// A free-standing function to get the current Physical Timer value
103///
104/// In some circumstances (e.g. timestamping a defmt log) you just want to get
105/// the time and don't want to drag around an object representing the whole
106/// timer.
107///
108/// This is just a thin wrapper around the relevant CPU register's read function
109/// - this just has a more discoverable name.
110pub fn read_physical_timer() -> u64 {
111    crate::register::CntPct::read().0
112}
113
114/// A free-standing function to get the current Virtual Timer value
115///
116/// In some circumstances (e.g. timestamping a defmt log) you just want to get
117/// the time and don't want to drag around an object representing the whole
118/// timer.
119///
120/// This is just a thin wrapper around the relevant CPU register's read function
121/// - this just has a more discoverable name.
122pub fn read_virtual_timer() -> u64 {
123    crate::register::CntVct::read().0
124}
125
126/// Describes the configuration for an Edvent
127#[derive(Debug, Clone, PartialEq, Eq)]
128pub struct EventConfig {
129    /// Controls which transition of the CNTVCT trigger bit, defined by EVNTI,
130    /// generates an event, when the event stream is enabled.
131    pub evntdir: EventDir,
132    /// How often does the event fire
133    pub rate: EventRate,
134}
135
136/// Describes the direction of an Event
137#[derive(Debug, Copy, Clone, PartialEq, Eq)]
138pub enum EventDir {
139    /// Event fires on a 1 -> 0 transition
140    HighLow,
141    /// Event fires on a 0 -> 1 transition
142    LowHigh,
143}
144
145/// How often does the event fire?
146#[derive(Debug, Copy, Clone, PartialEq, Eq)]
147#[repr(u8)]
148pub enum EventRate {
149    /// Fire every 1 ticks
150    _1 = 0,
151    /// Fire every 2 ticks
152    _2 = 1,
153    /// Fire every 4 ticks
154    _4 = 2,
155    /// Fire every 8 ticks
156    _8 = 3,
157    /// Fire every 16 ticks
158    _16 = 4,
159    /// Fire every 32 ticks
160    _32 = 5,
161    /// Fire every 64 ticks
162    _64 = 6,
163    /// Fire every 128 ticks
164    _128 = 7,
165    /// Fire every 256 ticks
166    _256 = 8,
167    /// Fire every 512 ticks
168    _512 = 9,
169    /// Fire every 1024 ticks
170    _1024 = 10,
171    /// Fire every 2048 ticks
172    _2048 = 11,
173    /// Fire every 4096 ticks
174    _4096 = 12,
175    /// Fire every 8192 ticks
176    _8192 = 13,
177    /// Fire every 16384 ticks
178    _16384 = 14,
179    /// Fire every 32768 ticks
180    _32768 = 15,
181}