pic32_hal/
coretimer.rs

1//! Access to the MIPS core timer and implementation of the `DelayMs/DelayUs`
2//! trait
3//!
4//! Uses the MIPS CP0 registers "count" and "compare".
5
6use crate::pac::INT; // interrupt controller
7use crate::time::Hertz;
8use embedded_hal::delay::DelayNs;
9use embedded_hal_0_2::blocking::delay::{DelayMs, DelayUs};
10
11use critical_section::Mutex;
12pub use mips_mcu::core_timer::read_count;
13use mips_mcu::core_timer::{read_compare, write_compare};
14
15use core::cell::Cell;
16
17const fn rounded_div_u32(a: u32, b: u32) -> u32 {
18    (a + b / 2) / b
19}
20
21/// Delay implementation based on read-only access to the core timer "count"
22/// register
23pub struct Delay {
24    ticks_per_us: u32,
25    nanos_per_tick: u32,
26}
27
28impl Delay {
29    pub const fn new(sysclock: Hertz) -> Self {
30        let ticks_per_us = sysclock.0 / 1_000_000 / 2;
31        let nanos_per_tick = rounded_div_u32(2 * 1_000_000_000, sysclock.0);
32        Delay {
33            ticks_per_us,
34            nanos_per_tick,
35        }
36    }
37}
38
39impl DelayMs<u32> for Delay {
40    fn delay_ms(&mut self, ms: u32) {
41        DelayUs::delay_us(self, ms * 1_000);
42    }
43}
44
45impl DelayMs<i32> for Delay {
46    fn delay_ms(&mut self, ms: i32) {
47        if ms >= 0 {
48            DelayUs::delay_us(self, (ms as u32) * 1000);
49        }
50    }
51}
52
53impl DelayMs<u16> for Delay {
54    fn delay_ms(&mut self, ms: u16) {
55        DelayMs::delay_ms(self, ms as u32);
56    }
57}
58
59impl DelayMs<u8> for Delay {
60    fn delay_ms(&mut self, ms: u8) {
61        DelayMs::delay_ms(self, ms as u32);
62    }
63}
64
65/// Pauses execution for `us` microseconds
66/// Less efficient implementation that can handle long delays but is not so
67/// well-suited for short delays in the order of a few µs.
68impl DelayUs<u32> for Delay {
69    fn delay_us(&mut self, us: u32) {
70        let mut total_ticks = us as u64 * self.ticks_per_us as u64;
71        while total_ticks != 0 {
72            let current_ticks = if total_ticks <= 0xffff_ffffu64 {
73                total_ticks as u32
74            } else {
75                0xffff_ffffu32
76            };
77            let start = read_count();
78            total_ticks -= current_ticks as u64;
79            while read_count().wrapping_sub(start) < current_ticks {}
80        }
81    }
82}
83
84/// Pauses execution for `us` microseconds
85/// A more efficient implementation suitable for short delays
86impl DelayUs<u16> for Delay {
87    fn delay_us(&mut self, us: u16) {
88        // read the count first for most accurate timing
89        let start = read_count();
90        let ticks = us as u32 * self.ticks_per_us;
91        while read_count().wrapping_sub(start) < ticks {}
92    }
93}
94
95impl DelayUs<u8> for Delay {
96    fn delay_us(&mut self, us: u8) {
97        DelayUs::delay_us(self, us as u16)
98    }
99}
100
101impl DelayNs for Delay {
102    fn delay_ns(&mut self, ns: u32) {
103        // read the count first for most accurate timing
104        let start = read_count();
105        let ticks = ns / self.nanos_per_tick;
106        while read_count().wrapping_sub(start) < ticks {}
107    }
108}
109
110/// Direct access to the MIPS core timer (CP0 timer) and related interrupt control
111///
112/// Can write to the "compare" register of MIPS core timer and can thus be
113/// instantiated only once. Write to the "count" register is not implemented to
114/// avoid conflicts with the `Delay` struct.
115pub struct Timer {}
116
117static TIMER: Mutex<Cell<Option<Timer>>> = Mutex::new(Cell::new(Some(Timer {})));
118
119impl Timer {
120    /// Get the `Timer` singleton. Panics if the singleton is not available.
121    pub fn take() -> Self {
122        let timeropt = critical_section::with(|cs| {
123            let cell = TIMER.borrow(cs);
124            cell.take()
125        });
126        timeropt.unwrap()
127    }
128
129    /// Return the `Timer` singleton.
130    pub fn free(self) {
131        critical_section::with(|cs| {
132            let cell = TIMER.borrow(cs);
133            cell.replace(Some(self));
134        });
135    }
136
137    /// Read Count register (CP0 register 9, select 0)
138    pub fn read_count(&self) -> u32 {
139        read_count()
140    }
141
142    /// Read Compare register (CP0 register 11, select 0)
143    pub fn read_compare(&self) -> u32 {
144        read_compare()
145    }
146
147    /// Write to Compare register (CPP0 register 11, select 0)
148    pub fn write_compare(&self, compare: u32) {
149        unsafe {
150            write_compare(compare);
151        }
152    }
153
154    /// Enable interrupts
155    pub fn enable_interrupts(&self, int: &INT) {
156        int.iec0set.write(|w| w.ctie().bit(true));
157    }
158
159    /// Disable interrupts and return whether interrupts were previously enabled.
160    pub fn disable_interrupts(&self, int: &INT) -> bool {
161        let was_enabled = int.iec0.read().ctie().bit();
162        int.iec0clr.write(|w| w.ctie().bit(true));
163        was_enabled
164    }
165
166    /// Set interrupt priority and sub priority. A priority level of 0 is the
167    /// lowest priority level and disables the interrupts.
168    pub fn set_interrupt_prio(&self, int: &INT, prio: u8, subprio: u8) {
169        int.ipc0
170            .modify(|_, w| unsafe { w.ctip().bits(prio).ctis().bits(subprio) });
171    }
172}