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}