diff --git a/rtic-monotonics/CHANGELOG.md b/rtic-monotonics/CHANGELOG.md index 9bbdc6c4c6..b13a3a9a44 100644 --- a/rtic-monotonics/CHANGELOG.md +++ b/rtic-monotonics/CHANGELOG.md @@ -7,6 +7,10 @@ For each category, *Added*, *Changed*, *Fixed* add new entries at the top! ## Unreleased +### Added + +- RP235x support + ## v2.0.2 - 2024-07-05 ### Fixed diff --git a/rtic-monotonics/Cargo.toml b/rtic-monotonics/Cargo.toml index 4828f0443b..8895fcb60d 100644 --- a/rtic-monotonics/Cargo.toml +++ b/rtic-monotonics/Cargo.toml @@ -20,6 +20,7 @@ repository = "https://github.com/rtic-rs/rtic" features = [ "cortex-m-systick", "rp2040", + "rp235x", "nrf52840", "imxrt_gpt1", "imxrt_gpt2", @@ -44,6 +45,9 @@ critical-section = { version = "1", optional = true } # RP2040 rp2040-pac = { version = "0.6", optional = true } +# RP235x +rp235x-pac = { version = "0.1.0", optional = true } + # nRF52 nrf52805-pac = { version = "0.12.2", optional = true } nrf52810-pac = { version = "0.12.2", optional = true } @@ -80,6 +84,9 @@ systick-64bit = [] # Timer peripheral on the RP2040 rp2040 = ["dep:cortex-m", "dep:rp2040-pac"] +# Timer peripheral on the RP235x +rp235x = ["dep:cortex-m", "dep:rp235x-pac"] + # nRF Timers and RTC nrf52805 = ["dep:cortex-m", "dep:nrf52805-pac", "dep:critical-section"] nrf52810 = ["dep:cortex-m", "dep:nrf52810-pac", "dep:critical-section"] diff --git a/rtic-monotonics/src/lib.rs b/rtic-monotonics/src/lib.rs index 9245f4539b..757e9018d3 100644 --- a/rtic-monotonics/src/lib.rs +++ b/rtic-monotonics/src/lib.rs @@ -45,6 +45,9 @@ pub mod systick; #[cfg(feature = "rp2040")] pub mod rp2040; +#[cfg(feature = "rp235x")] +pub mod rp235x; + #[cfg(feature = "imxrt")] pub mod imxrt; @@ -71,6 +74,7 @@ pub(crate) const fn cortex_logical2hw(logical: u8, nvic_prio_bits: u8) -> u8 { } #[cfg(any( + feature = "rp235x", feature = "rp2040", feature = "nrf52805", feature = "nrf52810", diff --git a/rtic-monotonics/src/rp235x.rs b/rtic-monotonics/src/rp235x.rs new file mode 100644 index 0000000000..7624d1d9fc --- /dev/null +++ b/rtic-monotonics/src/rp235x.rs @@ -0,0 +1,170 @@ +//! [`Monotonic`](rtic_time::Monotonic) implementation for RP235x's Timer peripheral +//! +//! +//! Always runs at a fixed rate of 1 MHz. +//! +//! # Example +//! +//! ``` +//! use rtic_monotonics::rp235x::prelude::*; +//! +//! rp235x_timer_monotonic!(Mono); +//! +//! fn init() { +//! # // This is normally provided by the selected PAC +//! # let timer = unsafe { core::mem::transmute(()) }; +//! # let mut resets = unsafe { core::mem::transmute(()) }; +//! # +//! // Start the monotonic +//! Mono::start(timer, &mut resets); +//! } +//! +//! async fn usage() { +//! loop { +//! // Use the monotonic +//! let timestamp = Mono::now(); +//! Mono::delay(100.millis()).await; +//! } +//! } +//! ``` + +/// Common definitions and traits for using the RP235x timer monotonic +pub mod prelude { + pub use crate::rp235x_timer_monotonic; + + pub use crate::Monotonic; + + pub use fugit::{self, ExtU64, ExtU64Ceil}; +} + +use crate::TimerQueueBackend; +use cortex_m::peripheral::NVIC; +use rp235x_pac::Interrupt; +pub use rp235x_pac::{timer0, RESETS, TIMER0}; +use rtic_time::timer_queue::TimerQueue; + +/// Timer implementing [`TimerQueueBackend`]. +pub struct TimerBackend; + +impl TimerBackend { + /// Starts the monotonic timer. + /// + /// **Do not use this function directly.** + /// + /// Use the prelude macros instead. + pub fn _start(timer: TIMER0, resets: &RESETS) { + resets.reset().modify(|_, w| w.timer0().clear_bit()); + while resets.reset_done().read().timer0().bit_is_clear() {} + timer.inte().modify(|_, w| w.alarm_0().bit(true)); + + TIMER_QUEUE.initialize(Self {}); + + unsafe { + crate::set_monotonic_prio(rp235x_pac::NVIC_PRIO_BITS, Interrupt::TIMER0_IRQ_0); + NVIC::unmask(Interrupt::TIMER0_IRQ_0); + } + } + + fn timer() -> &'static timer0::RegisterBlock { + unsafe { &*TIMER0::ptr() } + } +} + +static TIMER_QUEUE: TimerQueue = TimerQueue::new(); + +impl TimerQueueBackend for TimerBackend { + type Ticks = u64; + + fn now() -> Self::Ticks { + let timer = Self::timer(); + + let mut hi0 = timer.timerawh().read().bits(); + loop { + let low = timer.timerawl().read().bits(); + let hi1 = timer.timerawh().read().bits(); + if hi0 == hi1 { + break ((u64::from(hi0) << 32) | u64::from(low)); + } + hi0 = hi1; + } + } + + fn set_compare(instant: Self::Ticks) { + let now = Self::now(); + + const MAX: u64 = u32::MAX as u64; + + // Since the timer may or may not overflow based on the requested compare val, we check + // how many ticks are left. + // `wrapping_sub` takes care of the u64 integer overflow special case. + let val = if instant.wrapping_sub(now) <= MAX { + instant & MAX + } else { + 0 + }; + + Self::timer() + .alarm0() + .write(|w| unsafe { w.bits(val as u32) }); + } + + fn clear_compare_flag() { + Self::timer().intr().modify(|_, w| w.alarm_0().bit(true)); + } + + fn pend_interrupt() { + NVIC::pend(Interrupt::TIMER0_IRQ_0); + } + + fn timer_queue() -> &'static TimerQueue { + &TIMER_QUEUE + } +} + +/// Create an RP235x timer based monotonic and register the necessary interrupt for it. +/// +/// See [`crate::rp235x`] for more details. +/// +/// # Arguments +/// +/// * `name` - The name that the monotonic type will have. +#[macro_export] +macro_rules! rp235x_timer_monotonic { + ($name:ident) => { + /// A `Monotonic` based on the RP235x Timer peripheral. + pub struct $name; + + impl $name { + /// Starts the `Monotonic`. + /// + /// This method must be called only once. + pub fn start(timer: $crate::rp235x::TIMER0, resets: &$crate::rp235x::RESETS) { + #[no_mangle] + #[allow(non_snake_case)] + unsafe extern "C" fn TIMER0_IRQ_0() { + use $crate::TimerQueueBackend; + $crate::rp235x::TimerBackend::timer_queue().on_monotonic_interrupt(); + } + + $crate::rp235x::TimerBackend::_start(timer, resets); + } + } + + impl $crate::TimerQueueBasedMonotonic for $name { + type Backend = $crate::rp235x::TimerBackend; + type Instant = $crate::fugit::Instant< + ::Ticks, + 1, + 1_000_000, + >; + type Duration = $crate::fugit::Duration< + ::Ticks, + 1, + 1_000_000, + >; + } + + $crate::rtic_time::impl_embedded_hal_delay_fugit!($name); + $crate::rtic_time::impl_embedded_hal_async_delay_fugit!($name); + }; +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 40cbafa1c3..fe0c92a05a 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] channel = "stable" components = [ "rust-src", "rustfmt", "llvm-tools-preview" ] -targets = [ "thumbv6m-none-eabi", "thumbv7m-none-eabi", "thumbv8m.base-none-eabi", "thumbv8m.main-none-eabi" ] +targets = [ "thumbv6m-none-eabi", "thumbv7m-none-eabi", "thumbv8m.base-none-eabi", "thumbv8m.main-none-eabi" ]