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