aboutsummaryrefslogtreecommitdiff
path: root/src/peripheral/syst.rs
diff options
context:
space:
mode:
authorGravatar Jorge Aparicio <jorge@japaric.io> 2017-11-21 15:56:16 +0100
committerGravatar Jorge Aparicio <jorge@japaric.io> 2017-11-21 15:56:16 +0100
commitc6ed9ef43f6606f654c2392413ca8ed380a35056 (patch)
treed0291cc25ae95b99089fca9fb49c5b5826757413 /src/peripheral/syst.rs
parent7e05e189c5195303f8693d442b71754f956fc81f (diff)
downloadcortex-m-c6ed9ef43f6606f654c2392413ca8ed380a35056.tar.gz
cortex-m-c6ed9ef43f6606f654c2392413ca8ed380a35056.tar.zst
cortex-m-c6ed9ef43f6606f654c2392413ca8ed380a35056.zip
turn peripherals into scoped singletons
Diffstat (limited to 'src/peripheral/syst.rs')
-rw-r--r--src/peripheral/syst.rs137
1 files changed, 137 insertions, 0 deletions
diff --git a/src/peripheral/syst.rs b/src/peripheral/syst.rs
new file mode 100644
index 0000000..3f96208
--- /dev/null
+++ b/src/peripheral/syst.rs
@@ -0,0 +1,137 @@
+//! SysTick: System Timer
+
+use volatile_register::{RO, RW};
+
+/// 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 RegisterBlock {
+ /// Checks if counter is enabled
+ pub fn is_counter_enabled(&self) -> bool {
+ self.csr.read() & SYST_CSR_ENABLE != 0
+ }
+
+ /// Enables counter
+ pub fn enable_counter(&self) {
+ unsafe { self.csr.modify(|v| v | SYST_CSR_ENABLE) }
+ }
+
+ /// Disables counter
+ pub fn disable_counter(&self) {
+ unsafe { self.csr.modify(|v| v & !SYST_CSR_ENABLE) }
+ }
+
+ /// Checks if SysTick interrupt is enabled
+ pub fn is_interrupt_enabled(&self) -> bool {
+ self.csr.read() & SYST_CSR_TICKINT != 0
+ }
+
+ /// Enables SysTick interrupt
+ pub fn enable_interrupt(&self) {
+ unsafe { self.csr.modify(|v| v | SYST_CSR_TICKINT) }
+ }
+
+ /// Disables SysTick interrupt
+ pub fn disable_interrupt(&self) {
+ unsafe { self.csr.modify(|v| v & !SYST_CSR_TICKINT) }
+ }
+
+ /// Gets clock source
+ pub fn get_clock_source(&self) -> SystClkSource {
+ let clk_source_bit = self.csr.read() & SYST_CSR_CLKSOURCE != 0;
+ match clk_source_bit {
+ false => SystClkSource::External,
+ true => SystClkSource::Core,
+ }
+ }
+
+ /// Sets clock source
+ pub fn set_clock_source(&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) },
+ }
+ }
+
+ /// Checks if the counter wrapped (underflowed) since the last check
+ pub fn has_wrapped(&self) -> bool {
+ self.csr.read() & SYST_CSR_COUNTFLAG != 0
+ }
+
+ /// Gets reload value
+ pub fn get_reload(&self) -> u32 {
+ self.rvr.read()
+ }
+
+ /// Sets reload value
+ ///
+ /// Valid values are between `1` and `0x00ffffff`.
+ pub fn set_reload(&self, value: u32) {
+ unsafe { self.rvr.write(value) }
+ }
+
+ /// Gets current value
+ pub fn get_current(&self) -> u32 {
+ self.cvr.read()
+ }
+
+ /// Clears current value to 0
+ ///
+ /// After calling `clear_current()`, the next call to `has_wrapped()`
+ /// will return `false`.
+ pub fn clear_current(&self) {
+ unsafe { self.cvr.write(0) }
+ }
+
+ /// 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(&self) -> u32 {
+ self.calib.read() & SYST_COUNTER_MASK
+ }
+
+ /// 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(&self) -> bool {
+ self.calib.read() & SYST_CALIB_SKEW == 0
+ }
+
+ /// Checks if an external reference clock is available
+ pub fn has_reference_clock(&self) -> bool {
+ self.calib.read() & SYST_CALIB_NOREF == 0
+ }
+}