cortexm/systick.rs
1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Cortex-M SysTick Timer
6
7use core::cell::Cell;
8use kernel::utilities::registers::interfaces::{Readable, Writeable};
9use kernel::utilities::registers::{register_bitfields, FieldValue, ReadOnly, ReadWrite};
10use kernel::utilities::StaticRef;
11
12use core::num::NonZeroU32;
13
14/// The `SysTickFrequencyCapability` allows the holder to change the Cortex-M
15/// SysTick `hertz` field.
16pub unsafe trait SysTickFrequencyCapability {}
17
18#[repr(C)]
19struct SystickRegisters {
20 syst_csr: ReadWrite<u32, ControlAndStatus::Register>,
21 syst_rvr: ReadWrite<u32, ReloadValue::Register>,
22 syst_cvr: ReadWrite<u32, CurrentValue::Register>,
23 syst_calib: ReadOnly<u32, CalibrationValue::Register>,
24}
25
26register_bitfields![u32,
27 ControlAndStatus [
28 /// Returns 1 if timer counted to 0 since last time this was read.
29 COUNTFLAG 16,
30
31 /// Clock source is (0) External Clock or (1) Processor Clock.
32 CLKSOURCE 2,
33
34 /// Set to 1 to enable SysTick exception request.
35 TICKINT 1,
36
37 /// Enable the counter (1 == Enabled).
38 ENABLE 0
39 ],
40
41 ReloadValue [
42 /// Value loaded to `syst_csr` when counter is enabled and reaches 0.
43 RELOAD OFFSET(0) NUMBITS(24)
44 ],
45
46 CurrentValue [
47 /// Reads current value. Write of any value sets to 0.
48 CURRENT OFFSET(0) NUMBITS(24)
49 ],
50
51 CalibrationValue [
52 /// 0 if device provides reference clock to processor.
53 NOREF OFFSET(31) NUMBITS(1),
54
55 /// 0 if TENMS value is exact, 1 if inexact or not given.
56 SKEW OFFSET(30) NUMBITS(1),
57
58 /// Reload value for 10ms ticks, or 0 if no calibration.
59 TENMS OFFSET(0) NUMBITS(24)
60 ]
61];
62
63/// The ARM Cortex-M SysTick peripheral.
64///
65/// Documented in the Cortex-MX Devices Generic User Guide, Chapter 4.4.
66pub struct SysTick {
67 hertz: Cell<u32>,
68 external_clock: bool,
69}
70
71const BASE_ADDR: *const SystickRegisters = 0xE000E010 as *const SystickRegisters;
72const SYSTICK_BASE: StaticRef<SystickRegisters> = unsafe { StaticRef::new(BASE_ADDR) };
73
74impl SysTick {
75 /// Initialize the `SysTick` with default values.
76 ///
77 /// Use this constructor if the core implementation has a pre-calibration
78 /// value in hardware.
79 pub unsafe fn new() -> SysTick {
80 SysTick {
81 hertz: Cell::new(0),
82 external_clock: false,
83 }
84 }
85
86 /// Initialize the `SysTick` with an explicit clock speed.
87 ///
88 /// Use this constructor if the core implementation does not have a
89 /// pre-calibration value.
90 ///
91 /// * `clock_speed` - the frequency of SysTick tics in Hertz. For example,
92 /// if the SysTick is driven by the CPU clock, it is simply the CPU
93 /// speed.
94 pub unsafe fn new_with_calibration(clock_speed: u32) -> SysTick {
95 let res = SysTick::new();
96 res.hertz.set(clock_speed);
97 res
98 }
99
100 /// Initialize the `SysTick` with an explicit clock speed and external
101 /// source.
102 ///
103 /// Use this constructor if the core implementation does not have a
104 /// pre-calibration value and you need an external clock source for the
105 /// Systick.
106 ///
107 /// * `clock_speed` - the frequency of SysTick tics in Hertz. For example,
108 /// if the SysTick is driven by the CPU clock, it is simply the CPU
109 /// speed.
110 pub unsafe fn new_with_calibration_and_external_clock(clock_speed: u32) -> SysTick {
111 let mut res = SysTick::new();
112 res.hertz.set(clock_speed);
113 res.external_clock = true;
114 res
115 }
116
117 // Return the tic frequency in hertz.
118 //
119 // If the value is configured by the user using the `new_with_calibration`
120 // constructor return `self.hertz`. Otherwise, compute the frequency using
121 // the calibration value that is set in hardware.
122 fn hertz(&self) -> u32 {
123 let hz = self.hertz.get();
124 if hz != 0 {
125 hz
126 } else {
127 // The `tenms` register is the reload value for 10ms, so
128 // Hertz = number of tics in 1 second = tenms * 100
129 let tenms = SYSTICK_BASE.syst_calib.read(CalibrationValue::TENMS);
130 tenms * 100
131 }
132 }
133
134 /// Modifies the locally stored frequency.
135 ///
136 /// # Important
137 ///
138 /// This function does not change the actual systick frequency. This
139 /// function must be called only while the clock is not armed. When
140 /// changing the hardware systick frequency, the reload value register
141 /// should be updated and the current value register should be reset, in
142 /// order for the tick count to match the current frequency.
143 pub fn set_hertz(&self, clock_speed: u32, _capability: &dyn SysTickFrequencyCapability) {
144 self.hertz.set(clock_speed);
145 }
146}
147
148impl kernel::platform::scheduler_timer::SchedulerTimer for SysTick {
149 fn start(&self, us: NonZeroU32) {
150 let reload = {
151 // We need to convert from microseconds to native tics, which could
152 // overflow in 32-bit arithmetic. So we convert to 64-bit. 64-bit
153 // division is an expensive subroutine, but if `us` is a power of
154 // 10 the compiler will simplify it with the 1_000_000 divisor
155 // instead.
156 let us = us.get() as u64;
157 let hertz = self.hertz() as u64;
158
159 hertz * us / 1_000_000
160 };
161 let clock_source: FieldValue<u32, self::ControlAndStatus::Register> = if self.external_clock
162 {
163 // CLKSOURCE 0 --> external clock
164 ControlAndStatus::CLKSOURCE::CLEAR
165 } else {
166 // CLKSOURCE 1 --> internal clock
167 ControlAndStatus::CLKSOURCE::SET
168 };
169
170 // n.b.: 4.4.5 'hints and tips' suggests setting reload before value
171 SYSTICK_BASE
172 .syst_rvr
173 .write(ReloadValue::RELOAD.val(reload as u32));
174 SYSTICK_BASE.syst_cvr.set(0);
175
176 // OK, arm it. We really just need to set the TICKINT bit here, but
177 // can't use modify() because readying the CSR register will throw away
178 // evidence of expiration if one occurred, so we re-write entire value
179 // instead.
180 SYSTICK_BASE
181 .syst_csr
182 .write(ControlAndStatus::TICKINT::SET + ControlAndStatus::ENABLE::SET + clock_source);
183 }
184
185 fn reset(&self) {
186 SYSTICK_BASE.syst_csr.set(0);
187 SYSTICK_BASE.syst_rvr.set(0);
188 SYSTICK_BASE.syst_cvr.set(0);
189 }
190
191 fn arm(&self) {
192 let clock_source: FieldValue<u32, self::ControlAndStatus::Register> = if self.external_clock
193 {
194 // CLKSOURCE 0 --> external clock
195 ControlAndStatus::CLKSOURCE::CLEAR
196 } else {
197 // CLKSOURCE 1 --> internal clock
198 ControlAndStatus::CLKSOURCE::SET
199 };
200
201 // We really just need to set the TICKINT bit here, but can't `modify()`
202 // because readying the CSR register will throw away evidence of
203 // expiration if one occurred, so we re-write entire value instead.
204 SYSTICK_BASE
205 .syst_csr
206 .write(ControlAndStatus::TICKINT::SET + ControlAndStatus::ENABLE::SET + clock_source);
207 }
208
209 fn disarm(&self) {
210 let clock_source: FieldValue<u32, self::ControlAndStatus::Register> = if self.external_clock
211 {
212 // CLKSOURCE 0 --> external clock
213 ControlAndStatus::CLKSOURCE::CLEAR
214 } else {
215 // CLKSOURCE 1 --> internal clock
216 ControlAndStatus::CLKSOURCE::SET
217 };
218
219 // We really just need to set the TICKINT bit here, but can't `modify()`
220 // because readying the CSR register will throw away evidence of
221 // expiration if one occurred, so we re-write entire value instead.
222 SYSTICK_BASE
223 .syst_csr
224 .write(ControlAndStatus::TICKINT::CLEAR + ControlAndStatus::ENABLE::SET + clock_source);
225 }
226
227 fn get_remaining_us(&self) -> Option<NonZeroU32> {
228 // use u64 in case of overflow when multiplying by 1,000,000
229 let tics = SYSTICK_BASE.syst_cvr.read(CurrentValue::CURRENT) as u64;
230 if SYSTICK_BASE.syst_csr.is_set(ControlAndStatus::COUNTFLAG) {
231 None
232 } else {
233 let hertz = self.hertz() as u64;
234 NonZeroU32::new(((tics * 1_000_000) / hertz) as u32)
235 }
236 }
237}