diff --git a/embassy/Cargo.toml b/embassy/Cargo.toml index 6364f9902..87f54409a 100644 --- a/embassy/Cargo.toml +++ b/embassy/Cargo.toml @@ -5,7 +5,11 @@ authors = ["Dario Nieuwenhuis "] edition = "2018" [features] +default = ["tick-32768hz"] std = ["futures/std", "embassy-traits/std"] +tick-32768hz = [] +tick-1000hz = [] +tick-1mhz = [] defmt-trace = [] defmt-debug = [] @@ -26,6 +30,7 @@ embassy-macros = { version = "0.1.0", path = "../embassy-macros"} embassy-traits = { version = "0.1.0", path = "../embassy-traits"} atomic-polyfill = { version = "0.1.1" } critical-section = "0.2.1" +embedded-hal = "0.2.5" # Workaround https://github.com/japaric/cast.rs/pull/27 cast = { version = "=0.2.3", default-features = false } diff --git a/embassy/src/time/mod.rs b/embassy/src/time/mod.rs index 21b93d384..d50d9ef0d 100644 --- a/embassy/src/time/mod.rs +++ b/embassy/src/time/mod.rs @@ -10,8 +10,22 @@ pub use duration::Duration; pub use instant::Instant; pub use traits::*; -// TODO allow customizing, probably via Cargo features `tick-hz-32768` or something. -pub const TICKS_PER_SECOND: u64 = 32768; +#[cfg(any( + all(feature = "tick-32768hz", feature = "tick-1000hz"), + all(feature = "tick-32768hz", feature = "tick-1mhz"), +))] +compile_error!( + "Disable default-features to be able to use a tick rate other than the default (32768 Hz)" +); + +#[cfg(feature = "tick-1000hz")] +pub const TICKS_PER_SECOND: u64 = 1_000; + +#[cfg(feature = "tick-32768hz")] +pub const TICKS_PER_SECOND: u64 = 32_768; + +#[cfg(feature = "tick-1mhz")] +pub const TICKS_PER_SECOND: u64 = 1_000_000; static mut CLOCK: Option<&'static dyn Clock> = None; @@ -28,3 +42,56 @@ pub unsafe fn set_clock(clock: &'static dyn Clock) { pub(crate) fn now() -> u64 { unsafe { unwrap!(CLOCK, "No clock set").now() } } + +/// Type used for blocking delays through embedded-hal traits. +/// +/// For this interface to work, the Executor's clock must be correctly initialized before using it. +/// The delays are implemented in a "best-effort" way, meaning that the cpu will block for at least +/// the amount provided, but accuracy can be affected by many factors, including interrupt usage. +/// Make sure to use a suitable tick rate for your use case. The tick rate can be chosen through +/// features flags of this crate. +pub struct BlockingTimer; + +impl embedded_hal::blocking::delay::DelayMs for BlockingTimer { + fn delay_ms(&mut self, ms: u8) { + block_for(Duration::from_millis(ms as u64)) + } +} + +impl embedded_hal::blocking::delay::DelayMs for BlockingTimer { + fn delay_ms(&mut self, ms: u16) { + block_for(Duration::from_millis(ms as u64)) + } +} + +impl embedded_hal::blocking::delay::DelayMs for BlockingTimer { + fn delay_ms(&mut self, ms: u32) { + block_for(Duration::from_millis(ms as u64)) + } +} + +impl embedded_hal::blocking::delay::DelayUs for BlockingTimer { + fn delay_us(&mut self, us: u8) { + block_for(Duration::from_micros(us as u64)) + } +} + +impl embedded_hal::blocking::delay::DelayUs for BlockingTimer { + fn delay_us(&mut self, us: u16) { + block_for(Duration::from_micros(us as u64)) + } +} + +impl embedded_hal::blocking::delay::DelayUs for BlockingTimer { + fn delay_us(&mut self, us: u32) { + block_for(Duration::from_micros(us as u64)) + } +} + +/// Blocks the cpu for at least `duration`. +/// +/// For this interface to work, the Executor's clock must be correctly initialized before using it. +pub fn block_for(duration: Duration) { + let expires_at = Instant::now() + duration; + while Instant::now() < expires_at {} +}