e310x_hal/
delay.rs

1//! # Delays
2
3use crate::clock::Clocks;
4use e310x::CLINT;
5use embedded_hal::delay::DelayNs;
6use riscv::register::mip;
7
8/// Machine timer (mtime) as a busyloop delay provider
9#[derive(Default)]
10pub struct Delay;
11
12const TICKS_PER_SECOND: u64 = 32768;
13
14impl Delay {
15    /// Constructs a delay provider based on the machine timer (mtime)
16    pub fn new() -> Self {
17        Delay
18    }
19}
20
21impl DelayNs for Delay {
22    fn delay_ns(&mut self, ns: u32) {
23        let ticks = (ns as u64) * TICKS_PER_SECOND / 1_000_000_000;
24
25        let mtime = CLINT::mtimer().mtime;
26        let t = mtime.read() + ticks;
27        while mtime.read() < t {}
28    }
29}
30
31/// Machine timer (mtime) as a sleep delay provider using mtimecmp
32pub struct Sleep {
33    clock_freq: u32,
34}
35
36impl Sleep {
37    /// Constructs a delay provider using mtimecmp register to sleep
38    pub fn new(clocks: Clocks) -> Self {
39        Sleep {
40            clock_freq: clocks.lfclk().0,
41        }
42    }
43}
44
45impl DelayNs for Sleep {
46    fn delay_ns(&mut self, ns: u32) {
47        let ticks = (ns as u64) * u64::from(self.clock_freq) / 1_000_000_000;
48        let t = CLINT::mtimer().mtime.read() + ticks;
49
50        CLINT::mtimecmp0().write(t);
51
52        // Enable timer interrupt
53        unsafe { CLINT::mtimer_enable() };
54
55        // Wait For Interrupt will put CPU to sleep until an interrupt hits
56        // in our case when internal timer mtime value >= mtimecmp value
57        // after which empty handler gets called and we go into the
58        // next iteration of this loop
59        loop {
60            riscv::asm::wfi();
61
62            // check if we got the right interrupt cause, otherwise just loop back to wfi
63            if mip::read().mtimer() {
64                break;
65            }
66        }
67
68        // Clear timer interrupt
69        CLINT::mtimer_disable();
70    }
71}