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//! ARM Cortex-M SysTick peripheral.
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 speed.
93 pub unsafe fn new_with_calibration(clock_speed: u32) -> SysTick {
94 let res = SysTick::new();
95 res.hertz.set(clock_speed);
96 res
97 }
98
99 /// Initialize the `SysTick` with an explicit clock speed and external source
100 ///
101 /// Use this constructor if the core implementation does not have a
102 /// pre-calibration value and you need an external clock source for
103 /// the Systick.
104 ///
105 /// * `clock_speed` - the frequency of SysTick tics in Hertz. For example,
106 /// if the SysTick is driven by the CPU clock, it is simply the CPU speed.
107 pub unsafe fn new_with_calibration_and_external_clock(clock_speed: u32) -> SysTick {
108 let mut res = SysTick::new();
109 res.hertz.set(clock_speed);
110 res.external_clock = true;
111 res
112 }
113
114 // Return the tic frequency in hertz. If the value is configured by the
115 // user using the `new_with_calibration` constructor return `self.hertz`.
116 // Otherwise, compute the frequncy using the calibration value that is set
117 // in hardware.
118 fn hertz(&self) -> u32 {
119 let hz = self.hertz.get();
120 if hz != 0 {
121 hz
122 } else {
123 // The `tenms` register is the reload value for 10ms, so
124 // Hertz = number of tics in 1 second = tenms * 100
125 let tenms = SYSTICK_BASE.syst_calib.read(CalibrationValue::TENMS);
126 tenms * 100
127 }
128 }
129
130 /// Modifies the locally stored frequncy
131 ///
132 /// # Important
133 ///
134 /// This function does not change the actual systick frequency.
135 /// This function must be called only while the clock is not armed.
136 /// When changing the hardware systick frequency, the reload value register
137 /// should be updated and the current value register should be reset, in
138 /// order for the tick count to match the current frequency.
139 pub fn set_hertz(&self, clock_speed: u32, _capability: &dyn SysTickFrequencyCapability) {
140 self.hertz.set(clock_speed);
141 }
142}
143
144impl kernel::platform::scheduler_timer::SchedulerTimer for SysTick {
145 fn start(&self, us: NonZeroU32) {
146 let reload = {
147 // We need to convert from microseconds to native tics, which could overflow in 32-bit
148 // arithmetic. So we convert to 64-bit. 64-bit division is an expensive subroutine, but
149 // if `us` is a power of 10 the compiler will simplify it with the 1_000_000 divisor
150 // instead.
151 let us = us.get() as u64;
152 let hertz = self.hertz() as u64;
153
154 hertz * us / 1_000_000
155 };
156 let clock_source: FieldValue<u32, self::ControlAndStatus::Register> = if self.external_clock
157 {
158 // CLKSOURCE 0 --> external clock
159 ControlAndStatus::CLKSOURCE::CLEAR
160 } else {
161 // CLKSOURCE 1 --> internal clock
162 ControlAndStatus::CLKSOURCE::SET
163 };
164
165 // n.b.: 4.4.5 'hints and tips' suggests setting reload before value
166 SYSTICK_BASE
167 .syst_rvr
168 .write(ReloadValue::RELOAD.val(reload as u32));
169 SYSTICK_BASE.syst_cvr.set(0);
170
171 // OK, arm it
172 // We really just need to set the TICKINT bit here, but can't use modify() because
173 // readying the CSR register will throw away evidence of expiration if one
174 // occurred, so we re-write entire value instead.
175 SYSTICK_BASE
176 .syst_csr
177 .write(ControlAndStatus::TICKINT::SET + ControlAndStatus::ENABLE::SET + clock_source);
178 }
179
180 fn reset(&self) {
181 SYSTICK_BASE.syst_csr.set(0);
182 SYSTICK_BASE.syst_rvr.set(0);
183 SYSTICK_BASE.syst_cvr.set(0);
184 }
185
186 fn arm(&self) {
187 let clock_source: FieldValue<u32, self::ControlAndStatus::Register> = if self.external_clock
188 {
189 // CLKSOURCE 0 --> external clock
190 ControlAndStatus::CLKSOURCE::CLEAR
191 } else {
192 // CLKSOURCE 1 --> internal clock
193 ControlAndStatus::CLKSOURCE::SET
194 };
195
196 // We really just need to set the TICKINT bit here, but can't use modify() because
197 // readying the CSR register will throw away evidence of expiration if one
198 // occurred, so we re-write entire value instead.
199 SYSTICK_BASE
200 .syst_csr
201 .write(ControlAndStatus::TICKINT::SET + ControlAndStatus::ENABLE::SET + clock_source);
202 }
203
204 fn disarm(&self) {
205 let clock_source: FieldValue<u32, self::ControlAndStatus::Register> = if self.external_clock
206 {
207 // CLKSOURCE 0 --> external clock
208 ControlAndStatus::CLKSOURCE::CLEAR
209 } else {
210 // CLKSOURCE 1 --> internal clock
211 ControlAndStatus::CLKSOURCE::SET
212 };
213
214 // We really just need to set the TICKINT bit here, but can't use modify() because
215 // readying the CSR register will throw away evidence of expiration if one
216 // occurred, so we re-write entire value instead.
217 SYSTICK_BASE
218 .syst_csr
219 .write(ControlAndStatus::TICKINT::CLEAR + ControlAndStatus::ENABLE::SET + clock_source);
220 }
221
222 fn get_remaining_us(&self) -> Option<NonZeroU32> {
223 // use u64 in case of overflow when multiplying by 1,000,000
224 let tics = SYSTICK_BASE.syst_cvr.read(CurrentValue::CURRENT) as u64;
225 if SYSTICK_BASE.syst_csr.is_set(ControlAndStatus::COUNTFLAG) {
226 None
227 } else {
228 let hertz = self.hertz() as u64;
229 NonZeroU32::new(((tics * 1_000_000) / hertz) as u32)
230 }
231 }
232}