Skip to main content

cortex_m/peripheral/
syst.rs

1//! SysTick: System Timer
2//!
3//! # Example
4//!
5//! ```no_run
6//! use cortex_m::peripheral::{Peripherals, SYST};
7//!
8//! let core_periph = cortex_m::peripheral::Peripherals::take().unwrap();
9//! let mut syst = core_periph.SYST;
10//! syst.set_reload(0xffffff);
11//! syst.clear_current();
12//! syst.enable_counter();
13//!
14//! let syst_value: u32 = SYST::get_current();
15//! ```
16
17use volatile_register::{RO, RW};
18
19use crate::peripheral::SYST;
20
21/// Register block
22#[repr(C)]
23pub struct RegisterBlock {
24    /// Control and Status
25    pub csr: RW<u32>,
26    /// Reload Value
27    pub rvr: RW<u32>,
28    /// Current Value
29    pub cvr: RW<u32>,
30    /// Calibration Value
31    pub calib: RO<u32>,
32}
33
34/// SysTick clock source
35#[derive(Clone, Copy, Debug, PartialEq, Eq)]
36pub enum SystClkSource {
37    /// Core-provided clock
38    Core,
39    /// External reference clock
40    External,
41}
42
43const SYST_COUNTER_MASK: u32 = 0x00ff_ffff;
44
45const SYST_CSR_ENABLE: u32 = 1 << 0;
46const SYST_CSR_TICKINT: u32 = 1 << 1;
47const SYST_CSR_CLKSOURCE: u32 = 1 << 2;
48const SYST_CSR_COUNTFLAG: u32 = 1 << 16;
49
50const SYST_CALIB_SKEW: u32 = 1 << 30;
51const SYST_CALIB_NOREF: u32 = 1 << 31;
52
53impl SYST {
54    /// Clears current value to 0
55    ///
56    /// After calling `clear_current()`, the next call to `has_wrapped()`, unless called after the reload time (if the counter is enabled), will return `false`.
57    #[inline]
58    pub fn clear_current(&mut self) {
59        unsafe { self.cvr.write(0) }
60    }
61
62    /// Disables counter
63    #[inline]
64    pub fn disable_counter(&mut self) {
65        unsafe { self.csr.modify(|v| v & !SYST_CSR_ENABLE) }
66    }
67
68    /// Disables SysTick interrupt
69    #[inline]
70    pub fn disable_interrupt(&mut self) {
71        unsafe { self.csr.modify(|v| v & !SYST_CSR_TICKINT) }
72    }
73
74    /// Enables counter
75    ///
76    /// *NOTE* The reference manual indicates that:
77    ///
78    /// "The SysTick counter reload and current value are undefined at reset, the correct
79    /// initialization sequence for the SysTick counter is:
80    ///
81    /// - Program reload value
82    /// - Clear current value
83    /// - Program Control and Status register"
84    ///
85    /// The sequence translates to `self.set_reload(x); self.clear_current(); self.enable_counter()`
86    #[inline]
87    pub fn enable_counter(&mut self) {
88        unsafe { self.csr.modify(|v| v | SYST_CSR_ENABLE) }
89    }
90
91    /// Enables SysTick interrupt
92    #[inline]
93    pub fn enable_interrupt(&mut self) {
94        unsafe { self.csr.modify(|v| v | SYST_CSR_TICKINT) }
95    }
96
97    /// Gets clock source
98    ///
99    /// *NOTE* This takes `&mut self` because the read operation is side effectful and can clear the
100    /// bit that indicates that the timer has wrapped (cf. `SYST.has_wrapped`)
101    #[inline]
102    pub fn get_clock_source(&mut self) -> SystClkSource {
103        // NOTE(unsafe) atomic read with no side effects
104        if self.csr.read() & SYST_CSR_CLKSOURCE != 0 {
105            SystClkSource::Core
106        } else {
107            SystClkSource::External
108        }
109    }
110
111    /// Gets current value
112    #[inline]
113    pub fn get_current() -> u32 {
114        // NOTE(unsafe) atomic read with no side effects
115        unsafe { (*Self::PTR).cvr.read() }
116    }
117
118    /// Gets reload value
119    #[inline]
120    pub fn get_reload() -> u32 {
121        // NOTE(unsafe) atomic read with no side effects
122        unsafe { (*Self::PTR).rvr.read() }
123    }
124
125    /// Returns the reload value with which the counter would wrap once per 10
126    /// ms
127    ///
128    /// Returns `0` if the value is not known (e.g. because the clock can
129    /// change dynamically).
130    #[inline]
131    pub fn get_ticks_per_10ms() -> u32 {
132        // NOTE(unsafe) atomic read with no side effects
133        unsafe { (*Self::PTR).calib.read() & SYST_COUNTER_MASK }
134    }
135
136    /// Checks if an external reference clock is available
137    #[inline]
138    pub fn has_reference_clock() -> bool {
139        // NOTE(unsafe) atomic read with no side effects
140        unsafe { (*Self::PTR).calib.read() & SYST_CALIB_NOREF == 0 }
141    }
142
143    /// Checks if the counter wrapped (underflowed) since the last check
144    ///
145    /// *NOTE* This takes `&mut self` because the read operation is side effectful and will clear
146    /// the bit of the read register.
147    #[inline]
148    pub fn has_wrapped(&mut self) -> bool {
149        self.csr.read() & SYST_CSR_COUNTFLAG != 0
150    }
151
152    /// Checks if counter is enabled
153    ///
154    /// *NOTE* This takes `&mut self` because the read operation is side effectful and can clear the
155    /// bit that indicates that the timer has wrapped (cf. `SYST.has_wrapped`)
156    #[inline]
157    pub fn is_counter_enabled(&mut self) -> bool {
158        self.csr.read() & SYST_CSR_ENABLE != 0
159    }
160
161    /// Checks if SysTick interrupt is enabled
162    ///
163    /// *NOTE* This takes `&mut self` because the read operation is side effectful and can clear the
164    /// bit that indicates that the timer has wrapped (cf. `SYST.has_wrapped`)
165    #[inline]
166    pub fn is_interrupt_enabled(&mut self) -> bool {
167        self.csr.read() & SYST_CSR_TICKINT != 0
168    }
169
170    /// Checks if the calibration value is precise
171    ///
172    /// Returns `false` if using the reload value returned by
173    /// `get_ticks_per_10ms()` may result in a period significantly deviating
174    /// from 10 ms.
175    #[inline]
176    pub fn is_precise() -> bool {
177        // NOTE(unsafe) atomic read with no side effects
178        unsafe { (*Self::PTR).calib.read() & SYST_CALIB_SKEW == 0 }
179    }
180
181    /// Sets clock source
182    #[inline]
183    pub fn set_clock_source(&mut self, clk_source: SystClkSource) {
184        match clk_source {
185            SystClkSource::External => unsafe { self.csr.modify(|v| v & !SYST_CSR_CLKSOURCE) },
186            SystClkSource::Core => unsafe { self.csr.modify(|v| v | SYST_CSR_CLKSOURCE) },
187        }
188    }
189
190    /// Sets reload value
191    ///
192    /// Valid values are between `1` and `0x00ffffff`.
193    ///
194    /// *NOTE* To make the timer wrap every `N` ticks set the reload value to `N - 1`
195    #[inline]
196    pub fn set_reload(&mut self, value: u32) {
197        unsafe { self.rvr.write(value) }
198    }
199}