cortex_m/peripheral/
syst.rs

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