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
//! # Delay driver
//!
//! ## Overview
//! The Delay driver provides blocking delay functionalities using the
//! `SYSTIMER` peripheral for RISC-V devices and the built-in Xtensa timer for
//! Xtensa devices. This module implements the blocking [DelayMs] and [DelayUs]
//! traits from [embedded-hal].
//!
//! The delays are implemented in a "best-effort" way, meaning that the CPU will
//! block for at least the amount of time specified, but accuracy can be
//! affected by many factors, including interrupt usage.
//!
//! ## Example
//! ```no_run
//! let mut clocks = ClockControl::boot_defaults(system.clock_control).freeze();
//! let mut delay = Delay::new(&clocks);
//!
//! delay.delay_ms(1000 as u32);
//! ```
//!
//! [DelayMs]: embedded_hal::blocking::delay::DelayMs
//! [DelayUs]: embedded_hal::blocking::delay::DelayUs
//! [embedded-hal]: https://docs.rs/embedded-hal/latest/embedded_hal/
use fugit::HertzU64;
/// Delay driver
///
/// Uses the `SYSTIMER` peripheral internally for RISC-V devices, and the
/// built-in Xtensa timer for Xtensa devices.
#[derive(Clone, Copy)]
pub struct Delay {
freq: HertzU64,
}
impl<T> embedded_hal::blocking::delay::DelayMs<T> for Delay
where
T: Into<u32>,
{
fn delay_ms(&mut self, ms: T) {
for _ in 0..ms.into() {
self.delay_micros(1000u32);
}
}
}
impl<T> embedded_hal::blocking::delay::DelayUs<T> for Delay
where
T: Into<u32>,
{
fn delay_us(&mut self, us: T) {
self.delay_micros(us.into());
}
}
#[cfg(feature = "eh1")]
impl embedded_hal_1::delay::DelayNs for Delay {
fn delay_ns(&mut self, ns: u32) {
self.delay_nanos(ns);
}
}
#[cfg(riscv)]
mod implementation {
use super::*;
use crate::{clock::Clocks, systimer::SystemTimer};
impl Delay {
/// Create a new `Delay` instance
pub fn new(clocks: &Clocks) -> Self {
// The counters and comparators are driven using `XTAL_CLK`.
// The average clock frequency is fXTAL_CLK/2.5, which is 16 MHz.
// The timer counting is incremented by 1/16 μs on each `CNT_CLK` cycle.
Self {
freq: HertzU64::MHz(clocks.xtal_clock.to_MHz() as u64 * 10 / 25),
}
}
/// Delay for the specified number of microseconds
pub fn delay_micros(&self, us: u32) {
let t0 = SystemTimer::now();
let clocks = us as u64 * (self.freq / HertzU64::MHz(1));
while SystemTimer::now().wrapping_sub(t0) & SystemTimer::BIT_MASK <= clocks {}
}
/// Delay for the specified number of nanoseconds
pub fn delay_nanos(&self, ns: u32) {
let t0 = SystemTimer::now();
let clocks = ns as u64 * (self.freq / HertzU64::MHz(1)) / 1000;
while SystemTimer::now().wrapping_sub(t0) & SystemTimer::BIT_MASK <= clocks {}
}
}
}
#[cfg(xtensa)]
mod implementation {
use super::*;
use crate::clock::Clocks;
impl Delay {
/// Create a new `Delay` instance
pub fn new(clocks: &Clocks) -> Self {
Self {
freq: clocks.cpu_clock.into(),
}
}
/// Delay for the specified number of microseconds
pub fn delay_micros(&self, us: u32) {
let clocks = us as u64 * (self.freq / HertzU64::MHz(1));
xtensa_lx::timer::delay(clocks as u32);
}
/// Delay for the specified number of nanoseconds
pub fn delay_nanos(&self, ns: u32) {
let clocks = ns as u64 * (self.freq / HertzU64::MHz(1)) / 1000;
xtensa_lx::timer::delay(clocks as u32);
}
}
}