aboutsummaryrefslogtreecommitdiff
path: root/rtic-monotonics/src
diff options
context:
space:
mode:
authorMichael Zill <michael.zill@gmail.com>2024-09-29 06:19:37 +0200
committerGitHub <noreply@github.com>2024-09-29 04:19:37 +0000
commit6e68a5e6157204df4c79b0ea14a248cc8182863a (patch)
tree48f517d23af9ce64ae41a7e3cd29a64a7be2405d /rtic-monotonics/src
parent7b534b38e5aeb67f5fc0fa60f1ec1dd3956dc2bd (diff)
Feature/rp235x (#970)
* Add support for RP235x (Raspberry Pico 2) The xtask build system has not been updated therefor the components need to be build through Cargo * Remove unnecessary thumbv8mainhf-backend definition * Remove unnecessary thumbv8m.main-none-eabihf target * Update CHANGELOG * Remove default feature rp235x from rtic-monotonics * Remove features from rp235x-pac dependency in rtic-monotonics for rp235x
Diffstat (limited to 'rtic-monotonics/src')
-rw-r--r--rtic-monotonics/src/lib.rs4
-rw-r--r--rtic-monotonics/src/rp235x.rs170
2 files changed, 174 insertions, 0 deletions
diff --git a/rtic-monotonics/src/lib.rs b/rtic-monotonics/src/lib.rs
index 9245f45..757e901 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 0000000..7624d1d
--- /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<TimerBackend> = 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<Self> {
+ &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<
+ <Self::Backend as $crate::TimerQueueBackend>::Ticks,
+ 1,
+ 1_000_000,
+ >;
+ type Duration = $crate::fugit::Duration<
+ <Self::Backend as $crate::TimerQueueBackend>::Ticks,
+ 1,
+ 1_000_000,
+ >;
+ }
+
+ $crate::rtic_time::impl_embedded_hal_delay_fugit!($name);
+ $crate::rtic_time::impl_embedded_hal_async_delay_fugit!($name);
+ };
+}