1 | //! SysTick: System Timer |
2 | |
3 | use volatile_register::{RO, RW}; |
4 | |
5 | use crate::peripheral::SYST; |
6 | |
7 | /// Register block |
8 | #[repr (C)] |
9 | pub 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)] |
22 | pub enum SystClkSource { |
23 | /// Core-provided clock |
24 | Core, |
25 | /// External reference clock |
26 | External, |
27 | } |
28 | |
29 | const SYST_COUNTER_MASK: u32 = 0x00ff_ffff; |
30 | |
31 | const SYST_CSR_ENABLE: u32 = 1 << 0; |
32 | const SYST_CSR_TICKINT: u32 = 1 << 1; |
33 | const SYST_CSR_CLKSOURCE: u32 = 1 << 2; |
34 | const SYST_CSR_COUNTFLAG: u32 = 1 << 16; |
35 | |
36 | const SYST_CALIB_SKEW: u32 = 1 << 30; |
37 | const SYST_CALIB_NOREF: u32 = 1 << 31; |
38 | |
39 | impl 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 | } |
186 | |