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
//! ARM Cortex-M4 SysTick peripheral.

use core::cmp;
use kernel;
use kernel::common::VolatileCell;

struct Registers {
    control: VolatileCell<u32>,
    reload: VolatileCell<u32>,
    value: VolatileCell<u32>,
    calibration: VolatileCell<u32>,
}

/// The ARM Cortex-M4 SysTick peripheral
///
/// Documented in the Cortex-M4 Devices Generic User Guide, Chapter 4.4 (pagees
/// 249-252)
pub struct SysTick {
    regs: &'static Registers,
    hertz: u32,
}

const BASE_ADDR: *const Registers = 0xE000E010 as *const Registers;

impl SysTick {
    /// Initialize the `SysTick` with default values
    ///
    /// Use this constructor if the core implementation has a pre-calibration
    /// value in hardware.
    pub unsafe fn new() -> SysTick {
        SysTick {
            regs: &*BASE_ADDR,
            hertz: 0,
        }
    }

    /// Initialize the `SysTick` with an explicit clock speed
    ///
    /// Use this constructor if the core implementation does not have a
    /// pre-calibration value.
    ///
    ///   * `clock_speed` - the frequency of SysTick tics in Hertz. For example,
    ///   if the SysTick is driven by the CPU clock, it is simply the CPU speed.
    pub unsafe fn new_with_calibration(clock_speed: u32) -> SysTick {
        let mut res = SysTick::new();
        res.hertz = clock_speed;
        res
    }

    // Return the tic frequency in hertz. If the calibration value is set in
    // hardware, use `self.hertz`, which is set in the `new_with_calibration`
    // constructor.
    fn hertz(&self) -> u32 {
        let tenms = self.regs.calibration.get() & 0xffffff;
        if tenms == 0 {
            self.hertz
        } else {
            // The `tenms` register is the reload value for 10ms, so
            // Hertz = number of tics in 1 second = tenms * 100
            tenms * 100
        }
    }
}

impl kernel::SysTick for SysTick {
    fn set_timer(&self, us: u32) {
        let reload = if us == 0 {
            0
        } else {
            // only support values up to 1 second. That's twice as much as the
            // interface promises, so we're good. This makes computing hertz
            // safer
            let us = cmp::min(us, 1_000_000);
            let hertz = self.hertz();

            // What we actually want is:
            //
            // reload = hertz * us / 1000000
            //
            // But that can overflow if hertz and us are sufficiently large.
            // Dividing first may, instead, result in a reload value that's off
            // by a lot (because integer division rounds down).
            //
            // We use division to compute the reload value to avoid
            // multiplication overflows.
            //
            // 0 < us <= 1_000_000 so the divisions are never by zero
            //
            // As a result that the reload value might be slightly less
            // accurate. For example, with a 48MHz clock, the reload value for
            // 11ms should be 528000, but using integer division we'll get
            // 533333. A small price to pay for not crashing.
            hertz / (1_000_000 / us)
        };

        self.regs.value.set(0);
        self.regs.reload.set(reload);
    }

    fn value(&self) -> u32 {
        let hertz = self.hertz();
        let value = self.regs.value.get() & 0xffffff;

        // Just the opposite computation as in `set_timer` with the same
        // drawbacks
        if hertz > 1_000_000 {
            // More accurate
            value / (hertz / 1_000_000)
        } else {
            // Using the previous branch would divide by zero
            (value / hertz) / 1_000_000
        }
    }

    fn overflowed(&self) -> bool {
        self.regs.control.get() & 1 << 16 != 0
    }

    fn reset(&self) {
        self.regs.control.set(0);
        self.regs.reload.set(0);
        self.regs.value.set(0);
    }

    fn enable(&self, with_interrupt: bool) {
        if with_interrupt {
            self.regs.control.set(0b111);
        } else {
            self.regs.control.set(0b101);
        }
    }
}