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); } } }