      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

    //! 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) }
        }
    }

# Help

## Keyboard Shortcuts

`?`
  Show this help dialog
`S`
  Focus the search field
`↑`
  Move up in search results
`↓`
  Move down in search results
`↹`
  Switch tab
`⏎`
  Go to active search result
`+`
  Expand all sections
`-`
  Collapse all sections

## Search Tricks

Prefix searches with a type followed by a colon (e.g., `fn:`) to restrict the search to a given type.

Accepted types are: `fn`, `mod`, `struct`, `enum`, `trait`, `type`, `macro`, and `const`.

Search functions by type signature (e.g., `vec -> usize` or `* -> vec`)

Search multiple things at once by splitting your query with comma (e.g., `str,u8` or `String,struct:Vec,test`)