aboutsummaryrefslogtreecommitdiff
path: root/rtic-monotonics/src/nrf/timer.rs
diff options
context:
space:
mode:
authorFinomnis <Finomnis@users.noreply.github.com>2024-04-11 00:00:38 +0200
committerGitHub <noreply@github.com>2024-04-10 22:00:38 +0000
commit8c23e178f3838bcdd13662a2ffefd39ec144e869 (patch)
treef2d2cefcd6bb2876e74ee6035b5489a4a2d9590f /rtic-monotonics/src/nrf/timer.rs
parente4cc5fd17b8a2df332af0ee25c8bd7092e66afb0 (diff)
Monotonic rewrite (#874)
* Rework timer_queue and monotonic architecture Goals: * make Monotonic purely internal * make Monotonic purely tick passed, no fugit involved * create a wrapper struct in the user's code via a macro that then converts the "now" from the tick based monotonic to a fugit based timestamp We need to proxy the delay functions of the timer queue anyway, so we could simply perform the conversion in those proxy functions. * Update cargo.lock * Update readme of rtic-time * CI: ESP32: Redact esp_image: Too volatile * Fixup: Changelog double entry rebase mistake --------- Co-authored-by: Henrik Tjäder <henrik@tjaders.com>
Diffstat (limited to 'rtic-monotonics/src/nrf/timer.rs')
-rw-r--r--rtic-monotonics/src/nrf/timer.rs285
1 files changed, 161 insertions, 124 deletions
diff --git a/rtic-monotonics/src/nrf/timer.rs b/rtic-monotonics/src/nrf/timer.rs
index 7b760e4..60ee7dc 100644
--- a/rtic-monotonics/src/nrf/timer.rs
+++ b/rtic-monotonics/src/nrf/timer.rs
@@ -1,4 +1,4 @@
-//! [`Monotonic`] impl for the 32-bit timers of the nRF series.
+//! [`Monotonic`](rtic_time::Monotonic) implementation for the 32-bit timers of the nRF series.
//!
//! Not all timers are available on all parts. Ensure that only the available
//! timers are exposed by having the correct `nrf52*` feature enabled for `rtic-monotonics`.
@@ -6,139 +6,217 @@
//! # Example
//!
//! ```
-//! use rtic_monotonics::nrf::timer::*;
+//! use rtic_monotonics::nrf::timer::prelude::*;
+//! nrf_timer0_monotonic!(Mono);
//!
//! fn init() {
//! # // This is normally provided by the selected PAC
//! # let timer = unsafe { core::mem::transmute(()) };
-//! // Generate the required token
-//! let token = rtic_monotonics::create_nrf_timer0_monotonic_token!();
-//!
//! // Start the monotonic
-//! Timer0::start(timer, token);
+//! Mono::start(timer);
//! }
//!
//! async fn usage() {
//! loop {
//! // Use the monotonic
-//! Timer0::delay(100.millis()).await;
+//! let timestamp = Mono::now();
+//! Mono::delay(100.millis()).await;
//! }
//! }
//! ```
-use crate::{Monotonic, TimeoutError, TimerQueue};
-use atomic_polyfill::{AtomicU32, Ordering};
-use core::future::Future;
-pub use fugit::{self, ExtU64, ExtU64Ceil};
-use rtic_time::half_period_counter::calculate_now;
+/// Common definitions and traits for using the nRF Timer monotonics
+pub mod prelude {
+ pub use crate::nrf_timer0_monotonic;
+ pub use crate::nrf_timer1_monotonic;
+ pub use crate::nrf_timer2_monotonic;
+ #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
+ pub use crate::nrf_timer3_monotonic;
+ #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
+ pub use crate::nrf_timer4_monotonic;
+
+ pub use crate::Monotonic;
+ pub use fugit::{self, ExtU64, ExtU64Ceil};
+}
#[cfg(feature = "nrf52810")]
-use nrf52810_pac::{self as pac, Interrupt, TIMER0, TIMER1, TIMER2};
+#[doc(hidden)]
+pub use nrf52810_pac::{self as pac, TIMER0, TIMER1, TIMER2};
#[cfg(feature = "nrf52811")]
-use nrf52811_pac::{self as pac, Interrupt, TIMER0, TIMER1, TIMER2};
+#[doc(hidden)]
+pub use nrf52811_pac::{self as pac, TIMER0, TIMER1, TIMER2};
#[cfg(feature = "nrf52832")]
-use nrf52832_pac::{self as pac, Interrupt, TIMER0, TIMER1, TIMER2, TIMER3, TIMER4};
+#[doc(hidden)]
+pub use nrf52832_pac::{self as pac, TIMER0, TIMER1, TIMER2, TIMER3, TIMER4};
#[cfg(feature = "nrf52833")]
-use nrf52833_pac::{self as pac, Interrupt, TIMER0, TIMER1, TIMER2, TIMER3, TIMER4};
+#[doc(hidden)]
+pub use nrf52833_pac::{self as pac, TIMER0, TIMER1, TIMER2, TIMER3, TIMER4};
#[cfg(feature = "nrf52840")]
-use nrf52840_pac::{self as pac, Interrupt, TIMER0, TIMER1, TIMER2, TIMER3, TIMER4};
+#[doc(hidden)]
+pub use nrf52840_pac::{self as pac, TIMER0, TIMER1, TIMER2, TIMER3, TIMER4};
#[cfg(feature = "nrf5340-app")]
-use nrf5340_app_pac::{
- self as pac, Interrupt, TIMER0_NS as TIMER0, TIMER1_NS as TIMER1, TIMER2_NS as TIMER2,
+#[doc(hidden)]
+pub use nrf5340_app_pac::{
+ self as pac, TIMER0_NS as TIMER0, TIMER1_NS as TIMER1, TIMER2_NS as TIMER2,
};
#[cfg(feature = "nrf5340-net")]
-use nrf5340_net_pac::{
- self as pac, Interrupt, TIMER0_NS as TIMER0, TIMER1_NS as TIMER1, TIMER2_NS as TIMER2,
+#[doc(hidden)]
+pub use nrf5340_net_pac::{
+ self as pac, TIMER0_NS as TIMER0, TIMER1_NS as TIMER1, TIMER2_NS as TIMER2,
};
#[cfg(feature = "nrf9160")]
-use nrf9160_pac::{
- self as pac, Interrupt, TIMER0_NS as TIMER0, TIMER1_NS as TIMER1, TIMER2_NS as TIMER2,
+#[doc(hidden)]
+pub use nrf9160_pac::{self as pac, TIMER0_NS as TIMER0, TIMER1_NS as TIMER1, TIMER2_NS as TIMER2};
+
+use atomic_polyfill::{AtomicU32, Ordering};
+use rtic_time::{
+ half_period_counter::calculate_now,
+ timer_queue::{TimerQueue, TimerQueueBackend},
};
#[doc(hidden)]
#[macro_export]
macro_rules! __internal_create_nrf_timer_interrupt {
- ($mono_timer:ident, $timer:ident, $timer_token:ident) => {{
+ ($mono_backend:ident, $timer:ident) => {
#[no_mangle]
#[allow(non_snake_case)]
unsafe extern "C" fn $timer() {
- $crate::nrf::timer::$mono_timer::__tq().on_monotonic_interrupt();
+ use $crate::TimerQueueBackend;
+ $crate::nrf::timer::$mono_backend::timer_queue().on_monotonic_interrupt();
}
+ };
+}
- pub struct $timer_token;
+#[doc(hidden)]
+#[macro_export]
+macro_rules! __internal_create_nrf_timer_struct {
+ ($name:ident, $mono_backend:ident, $timer:ident, $tick_rate_hz:expr) => {
+ /// A `Monotonic` based on the nRF Timer peripheral.
+ struct $name;
+
+ impl $name {
+ /// Starts the `Monotonic`.
+ ///
+ /// This method must be called only once.
+ pub fn start(timer: $crate::nrf::timer::$timer) {
+ $crate::__internal_create_nrf_timer_interrupt!($mono_backend, $timer);
+
+ const PRESCALER: u8 = match $tick_rate_hz {
+ 16_000_000 => 0,
+ 8_000_000 => 1,
+ 4_000_000 => 2,
+ 2_000_000 => 3,
+ 1_000_000 => 4,
+ 500_000 => 5,
+ 250_000 => 6,
+ 125_000 => 7,
+ 62_500 => 8,
+ 31_250 => 9,
+ _ => panic!("Timer cannot run at desired tick rate!"),
+ };
+
+ $crate::nrf::timer::$mono_backend::_start(timer, PRESCALER);
+ }
+ }
- unsafe impl $crate::InterruptToken<$crate::nrf::timer::$mono_timer> for $timer_token {}
+ impl $crate::TimerQueueBasedMonotonic for $name {
+ type Backend = $crate::nrf::timer::$mono_backend;
+ type Instant = $crate::fugit::Instant<
+ <Self::Backend as $crate::TimerQueueBackend>::Ticks,
+ 1,
+ { $tick_rate_hz },
+ >;
+ type Duration = $crate::fugit::Duration<
+ <Self::Backend as $crate::TimerQueueBackend>::Ticks,
+ 1,
+ { $tick_rate_hz },
+ >;
+ }
- $timer_token
- }};
+ $crate::rtic_time::impl_embedded_hal_delay_fugit!($name);
+ $crate::rtic_time::impl_embedded_hal_async_delay_fugit!($name);
+ };
}
-/// Register the Timer0 interrupt for the monotonic.
+/// Create an Timer0 based monotonic and register the TIMER0 interrupt for it.
+///
+/// See [`crate::nrf::timer`] for more details.
#[macro_export]
-macro_rules! create_nrf_timer0_monotonic_token {
- () => {{
- $crate::__internal_create_nrf_timer_interrupt!(Timer0, TIMER0, Timer0Token)
- }};
+macro_rules! nrf_timer0_monotonic {
+ ($name:ident, $tick_rate_hz:expr) => {
+ $crate::__internal_create_nrf_timer_struct!($name, Timer0Backend, TIMER0, $tick_rate_hz);
+ };
}
-/// Register the Timer1 interrupt for the monotonic.
+/// Create an Timer1 based monotonic and register the TIMER1 interrupt for it.
+///
+/// See [`crate::nrf::timer`] for more details.
#[macro_export]
-macro_rules! create_nrf_timer1_monotonic_token {
- () => {{
- $crate::__internal_create_nrf_timer_interrupt!(Timer1, TIMER1, Timer1Token)
- }};
+macro_rules! nrf_timer1_monotonic {
+ ($name:ident, $tick_rate_hz:expr) => {
+ $crate::__internal_create_nrf_timer_struct!($name, Timer1Backend, TIMER1, $tick_rate_hz);
+ };
}
-/// Register the Timer2 interrupt for the monotonic.
+/// Create an Timer2 based monotonic and register the TIMER2 interrupt for it.
+///
+/// See [`crate::nrf::timer`] for more details.
#[macro_export]
-macro_rules! create_nrf_timer2_monotonic_token {
- () => {{
- $crate::__internal_create_nrf_timer_interrupt!(Timer2, TIMER2, Timer2Token)
- }};
+macro_rules! nrf_timer2_monotonic {
+ ($name:ident, $tick_rate_hz:expr) => {
+ $crate::__internal_create_nrf_timer_struct!($name, Timer2Backend, TIMER2, $tick_rate_hz);
+ };
}
-/// Register the Timer3 interrupt for the monotonic.
+/// Create an Timer3 based monotonic and register the TIMER3 interrupt for it.
+///
+/// See [`crate::nrf::timer`] for more details.
#[cfg_attr(
docsrs,
doc(cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840")))
)]
#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
#[macro_export]
-macro_rules! create_nrf_timer3_monotonic_token {
- () => {{
- $crate::__internal_create_nrf_timer_interrupt!(Timer3, TIMER3, Timer3Token)
- }};
+macro_rules! nrf_timer3_monotonic {
+ ($name:ident, $tick_rate_hz:expr) => {
+ $crate::__internal_create_nrf_timer_struct!($name, Timer3Backend, TIMER3, $tick_rate_hz);
+ };
}
-/// Register the Timer4 interrupt for the monotonic.
+/// Create an Timer4 based monotonic and register the TIMER4 interrupt for it.
+///
+/// See [`crate::nrf::timer`] for more details.
#[cfg_attr(
docsrs,
doc(cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840")))
)]
#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
#[macro_export]
-macro_rules! create_nrf_timer4_monotonic_token {
- () => {{
- $crate::__internal_create_nrf_timer_interrupt!(Timer4, TIMER4, Timer4Token)
- }};
+macro_rules! nrf_timer4_monotonic {
+ ($name:ident, $tick_rate_hz:expr) => {
+ $crate::__internal_create_nrf_timer_struct!($name, Timer4Backend, TIMER4, $tick_rate_hz);
+ };
}
macro_rules! make_timer {
- ($mono_name:ident, $timer:ident, $overflow:ident, $tq:ident$(, doc: ($($doc:tt)*))?) => {
- /// Monotonic timer queue implementation.
+ ($backend_name:ident, $timer:ident, $overflow:ident, $tq:ident$(, doc: ($($doc:tt)*))?) => {
+ /// Timer peripheral based [`TimerQueueBackend`].
$(
#[cfg_attr(docsrs, doc(cfg($($doc)*)))]
)?
- pub struct $mono_name;
+ pub struct $backend_name;
static $overflow: AtomicU32 = AtomicU32::new(0);
- static $tq: TimerQueue<$mono_name> = TimerQueue::new();
-
- impl $mono_name {
- /// Start the timer monotonic.
- pub fn start(timer: $timer, _interrupt_token: impl crate::InterruptToken<Self>) {
- // 1 MHz
- timer.prescaler.write(|w| unsafe { w.prescaler().bits(4) });
+ static $tq: TimerQueue<$backend_name> = TimerQueue::new();
+
+ impl $backend_name {
+ /// Starts the timer.
+ ///
+ /// **Do not use this function directly.**
+ ///
+ /// Use the prelude macros instead.
+ pub fn _start(timer: $timer, prescaler: u8) {
+ timer.prescaler.write(|w| unsafe { w.prescaler().bits(prescaler) });
timer.bitmode.write(|w| w.bitmode()._32bit());
// Disable interrupts, as preparation
@@ -184,70 +262,25 @@ macro_rules! make_timer {
// plus we are not using any external shared resources so we won't impact
// basepri/source masking based critical sections.
unsafe {
- crate::set_monotonic_prio(pac::NVIC_PRIO_BITS, Interrupt::$timer);
- pac::NVIC::unmask(Interrupt::$timer);
+ crate::set_monotonic_prio(pac::NVIC_PRIO_BITS, pac::Interrupt::$timer);
+ pac::NVIC::unmask(pac::Interrupt::$timer);
}
}
-
- /// Used to access the underlying timer queue
- #[doc(hidden)]
- pub fn __tq() -> &'static TimerQueue<$mono_name> {
- &$tq
- }
-
- /// Timeout at a specific time.
- #[inline]
- pub async fn timeout_at<F: Future>(
- instant: <Self as Monotonic>::Instant,
- future: F,
- ) -> Result<F::Output, TimeoutError> {
- $tq.timeout_at(instant, future).await
- }
-
- /// Timeout after a specific duration.
- #[inline]
- pub async fn timeout_after<F: Future>(
- duration: <Self as Monotonic>::Duration,
- future: F,
- ) -> Result<F::Output, TimeoutError> {
- $tq.timeout_after(duration, future).await
- }
-
- /// Delay for some duration of time.
- #[inline]
- pub async fn delay(duration: <Self as Monotonic>::Duration) {
- $tq.delay(duration).await;
- }
-
- /// Delay to some specific time instant.
- #[inline]
- pub async fn delay_until(instant: <Self as Monotonic>::Instant) {
- $tq.delay_until(instant).await;
- }
}
- rtic_time::embedded_hal_delay_impl_fugit64!($mono_name);
-
- #[cfg(feature = "embedded-hal-async")]
- rtic_time::embedded_hal_async_delay_impl_fugit64!($mono_name);
+ impl TimerQueueBackend for $backend_name {
+ type Ticks = u64;
- impl Monotonic for $mono_name {
- const ZERO: Self::Instant = Self::Instant::from_ticks(0);
- const TICK_PERIOD: Self::Duration = Self::Duration::from_ticks(1);
-
- type Instant = fugit::TimerInstantU64<1_000_000>;
- type Duration = fugit::TimerDurationU64<1_000_000>;
-
- fn now() -> Self::Instant {
+ fn now() -> Self::Ticks {
let timer = unsafe { &*$timer::PTR };
- Self::Instant::from_ticks(calculate_now(
+ calculate_now(
|| $overflow.load(Ordering::Relaxed),
|| {
timer.tasks_capture[3].write(|w| unsafe { w.bits(1) });
timer.cc[3].read().bits()
}
- ))
+ )
}
fn on_interrupt() {
@@ -268,9 +301,9 @@ macro_rules! make_timer {
}
}
- fn set_compare(instant: Self::Instant) {
+ fn set_compare(instant: Self::Ticks) {
let timer = unsafe { &*$timer::PTR };
- timer.cc[0].write(|w| unsafe { w.cc().bits(instant.ticks() as u32) });
+ timer.cc[0].write(|w| unsafe { w.cc().bits(instant as u32) });
}
fn clear_compare_flag() {
@@ -279,16 +312,20 @@ macro_rules! make_timer {
}
fn pend_interrupt() {
- pac::NVIC::pend(Interrupt::$timer);
+ pac::NVIC::pend(pac::Interrupt::$timer);
+ }
+
+ fn timer_queue() -> &'static TimerQueue<$backend_name> {
+ &$tq
}
}
};
}
-make_timer!(Timer0, TIMER0, TIMER0_OVERFLOWS, TIMER0_TQ);
-make_timer!(Timer1, TIMER1, TIMER1_OVERFLOWS, TIMER1_TQ);
-make_timer!(Timer2, TIMER2, TIMER2_OVERFLOWS, TIMER2_TQ);
+make_timer!(Timer0Backend, TIMER0, TIMER0_OVERFLOWS, TIMER0_TQ);
+make_timer!(Timer1Backend, TIMER1, TIMER1_OVERFLOWS, TIMER1_TQ);
+make_timer!(Timer2Backend, TIMER2, TIMER2_OVERFLOWS, TIMER2_TQ);
#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
-make_timer!(Timer3, TIMER3, TIMER3_OVERFLOWS, TIMER3_TQ, doc: (any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840")));
+make_timer!(Timer3Backend, TIMER3, TIMER3_OVERFLOWS, TIMER3_TQ, doc: (any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840")));
#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
-make_timer!(Timer4, TIMER4, TIMER4_OVERFLOWS, TIMER4_TQ, doc: (any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840")));
+make_timer!(Timer4Backend, TIMER4, TIMER4_OVERFLOWS, TIMER4_TQ, doc: (any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840")));