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}