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}