Select Git revision
syst.rs 5.37 KiB
//! SysTick: System Timer
use volatile_register::{RO, RW};
use 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)]
pub enum SystClkSource {
/// Core-provided clock
Core,
/// External reference clock
External,
}
const SYST_COUNTER_MASK: u32 = 0x00ffffff;
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`.
pub fn clear_current(&mut self) {
unsafe { self.cvr.write(0) }
}
/// Disables counter
pub fn disable_counter(&mut self) {
unsafe { self.csr.modify(|v| v & !SYST_CSR_ENABLE) }
}
/// Disables SysTick interrupt
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()`
pub fn enable_counter(&mut self) {
unsafe { self.csr.modify(|v| v | SYST_CSR_ENABLE) }
}
/// Enables SysTick interrupt
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`)
pub fn get_clock_source(&mut self) -> SystClkSource {
// NOTE(unsafe) atomic read with no side effects
let clk_source_bit = self.csr.read() & SYST_CSR_CLKSOURCE != 0;
match clk_source_bit {
false => SystClkSource::External,
true => SystClkSource::Core,
}
}
/// Gets current value
pub fn get_current() -> u32 {
// NOTE(unsafe) atomic read with no side effects
unsafe { (*Self::ptr()).cvr.read() }
}
/// Gets reload value
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).
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
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.
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`)
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`)
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.
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
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`
pub fn set_reload(&mut self, value: u32) {
unsafe { self.rvr.write(value) }
}
}