diff options
| author | Finomnis <Finomnis@users.noreply.github.com> | 2024-04-11 00:00:38 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-04-10 22:00:38 +0000 |
| commit | 8c23e178f3838bcdd13662a2ffefd39ec144e869 (patch) | |
| tree | f2d2cefcd6bb2876e74ee6035b5489a4a2d9590f /rtic-monotonics/src/nrf | |
| parent | e4cc5fd17b8a2df332af0ee25c8bd7092e66afb0 (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')
| -rw-r--r-- | rtic-monotonics/src/nrf/rtc.rs | 255 | ||||
| -rw-r--r-- | rtic-monotonics/src/nrf/timer.rs | 285 |
2 files changed, 301 insertions, 239 deletions
diff --git a/rtic-monotonics/src/nrf/rtc.rs b/rtic-monotonics/src/nrf/rtc.rs index d425b11..39b26c4 100644 --- a/rtic-monotonics/src/nrf/rtc.rs +++ b/rtic-monotonics/src/nrf/rtc.rs @@ -1,96 +1,152 @@ -//! [`Monotonic`] implementation for the nRF Real Time Clocks (RTC). +//! [`Monotonic`](rtic_time::Monotonic) implementation for the nRF Real Time Clocks (RTC). //! //! # Example //! //! ``` -//! use rtic_monotonics::nrf::rtc::*; +//! use rtic_monotonics::nrf::rtc::prelude::*; +//! nrf_rtc0_monotonic!(Mono); //! //! fn init() { //! # // This is normally provided by the selected PAC //! # let rtc = unsafe { core::mem::transmute(()) }; -//! // Generate the required token -//! let token = rtic_monotonics::create_nrf_rtc0_monotonic_token!(); -//! //! // Start the monotonic -//! Rtc0::start(rtc, token); +//! Mono::start(rtc); //! } //! //! async fn usage() { //! loop { //! // Use the monotonic -//! Rtc0::delay(100.millis()).await; +//! let timestamp = Mono::now(); +//! Mono::delay(100.millis()).await; //! } //! } //! ``` +/// Common definitions and traits for using the nRF RTC monotonics +pub mod prelude { + pub use crate::nrf_rtc0_monotonic; + pub use crate::nrf_rtc1_monotonic; + #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] + pub use crate::nrf_rtc2_monotonic; + + pub use crate::Monotonic; + pub use fugit::{self, ExtU64, ExtU64Ceil}; +} + #[cfg(feature = "nrf52810")] -use nrf52810_pac::{self as pac, Interrupt, RTC0, RTC1}; +#[doc(hidden)] +pub use nrf52810_pac::{self as pac, RTC0, RTC1}; #[cfg(feature = "nrf52811")] -use nrf52811_pac::{self as pac, Interrupt, RTC0, RTC1}; +#[doc(hidden)] +pub use nrf52811_pac::{self as pac, RTC0, RTC1}; #[cfg(feature = "nrf52832")] -use nrf52832_pac::{self as pac, Interrupt, RTC0, RTC1, RTC2}; +#[doc(hidden)] +pub use nrf52832_pac::{self as pac, RTC0, RTC1, RTC2}; #[cfg(feature = "nrf52833")] -use nrf52833_pac::{self as pac, Interrupt, RTC0, RTC1, RTC2}; +#[doc(hidden)] +pub use nrf52833_pac::{self as pac, RTC0, RTC1, RTC2}; #[cfg(feature = "nrf52840")] -use nrf52840_pac::{self as pac, Interrupt, RTC0, RTC1, RTC2}; +#[doc(hidden)] +pub use nrf52840_pac::{self as pac, RTC0, RTC1, RTC2}; #[cfg(feature = "nrf5340-app")] -use nrf5340_app_pac::{self as pac, Interrupt, RTC0_NS as RTC0, RTC1_NS as RTC1}; +#[doc(hidden)] +pub use nrf5340_app_pac::{self as pac, RTC0_NS as RTC0, RTC1_NS as RTC1}; #[cfg(feature = "nrf5340-net")] -use nrf5340_net_pac::{self as pac, Interrupt, RTC0_NS as RTC0, RTC1_NS as RTC1}; +#[doc(hidden)] +pub use nrf5340_net_pac::{self as pac, RTC0_NS as RTC0, RTC1_NS as RTC1}; #[cfg(feature = "nrf9160")] -use nrf9160_pac::{self as pac, Interrupt, RTC0_NS as RTC0, RTC1_NS as RTC1}; +#[doc(hidden)] +pub use nrf9160_pac::{self as pac, RTC0_NS as RTC0, RTC1_NS as RTC1}; -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; +use rtic_time::{ + half_period_counter::calculate_now, + timer_queue::{TimerQueue, TimerQueueBackend}, +}; #[doc(hidden)] #[macro_export] macro_rules! __internal_create_nrf_rtc_interrupt { - ($mono_timer:ident, $rtc:ident, $rtc_token:ident) => {{ + ($mono_backend:ident, $rtc:ident) => { #[no_mangle] #[allow(non_snake_case)] unsafe extern "C" fn $rtc() { - $crate::nrf::rtc::$mono_timer::__tq().on_monotonic_interrupt(); + use $crate::TimerQueueBackend; + $crate::nrf::rtc::$mono_backend::timer_queue().on_monotonic_interrupt(); } + }; +} - pub struct $rtc_token; +#[doc(hidden)] +#[macro_export] +macro_rules! __internal_create_nrf_rtc_struct { + ($name:ident, $mono_backend:ident, $timer:ident) => { + /// A `Monotonic` based on the nRF RTC peripheral. + struct $name; + + impl $name { + /// Starts the `Monotonic`. + /// + /// This method must be called only once. + pub fn start(rtc: $crate::nrf::rtc::$timer) { + $crate::__internal_create_nrf_rtc_interrupt!($mono_backend, $timer); + + $crate::nrf::rtc::$mono_backend::_start(rtc); + } + } - unsafe impl $crate::InterruptToken<$crate::nrf::rtc::$mono_timer> for $rtc_token {} + impl $crate::TimerQueueBasedMonotonic for $name { + type Backend = $crate::nrf::rtc::$mono_backend; + type Instant = $crate::fugit::Instant< + <Self::Backend as $crate::TimerQueueBackend>::Ticks, + 1, + 32_768, + >; + type Duration = $crate::fugit::Duration< + <Self::Backend as $crate::TimerQueueBackend>::Ticks, + 1, + 32_768, + >; + } - $rtc_token - }}; + $crate::rtic_time::impl_embedded_hal_delay_fugit!($name); + $crate::rtic_time::impl_embedded_hal_async_delay_fugit!($name); + }; } -/// Register the Rtc0 interrupt for the monotonic. +/// Create an RTC0 based monotonic and register the RTC0 interrupt for it. +/// +/// See [`crate::nrf::rtc`] for more details. #[macro_export] -macro_rules! create_nrf_rtc0_monotonic_token { - () => {{ - $crate::__internal_create_nrf_rtc_interrupt!(Rtc0, RTC0, Rtc0Token) - }}; +macro_rules! nrf_rtc0_monotonic { + ($name:ident) => { + $crate::__internal_create_nrf_rtc_struct!($name, Rtc0Backend, RTC0); + }; } -/// Register the Rtc1 interrupt for the monotonic. +/// Create an RTC1 based monotonic and register the RTC1 interrupt for it. +/// +/// See [`crate::nrf::rtc`] for more details. #[macro_export] -macro_rules! create_nrf_rtc1_monotonic_token { - () => {{ - $crate::__internal_create_nrf_rtc_interrupt!(Rtc1, RTC1, Rtc1Token) - }}; +macro_rules! nrf_rtc1_monotonic { + ($name:ident) => { + $crate::__internal_create_nrf_rtc_struct!($name, Rtc1Backend, RTC1); + }; } -/// Register the Rtc2 interrupt for the monotonic. +/// Create an RTC2 based monotonic and register the RTC2 interrupt for it. +/// +/// See [`crate::nrf::rtc`] for more details. #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] #[cfg_attr( docsrs, doc(cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))) )] #[macro_export] -macro_rules! create_nrf_rtc2_monotonic_token { - () => {{ - $crate::__internal_create_nrf_rtc_interrupt!(Rtc2, RTC2, Rtc2Token) - }}; +macro_rules! nrf_rtc2_monotonic { + ($name:ident) => { + $crate::__internal_create_nrf_rtc_struct!($name, Rtc2Backend, RTC2); + }; } struct TimerValueU24(u32); @@ -104,19 +160,23 @@ impl From<TimerValueU24> for u64 { } macro_rules! make_rtc { - ($mono_name:ident, $rtc:ident, $overflow:ident, $tq:ident$(, doc: ($($doc:tt)*))?) => { - /// Monotonic timer queue implementation. + ($backend_name:ident, $rtc:ident, $overflow:ident, $tq:ident$(, doc: ($($doc:tt)*))?) => { + /// RTC 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(rtc: $rtc, _interrupt_token: impl crate::InterruptToken<Self>) { + 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(rtc: $rtc) { unsafe { rtc.prescaler.write(|w| w.bits(0)) }; // Disable interrupts, as preparation @@ -166,67 +226,21 @@ macro_rules! make_rtc { // 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::$rtc); - pac::NVIC::unmask(Interrupt::$rtc); + crate::set_monotonic_prio(pac::NVIC_PRIO_BITS, pac::Interrupt::$rtc); + pac::NVIC::unmask(pac::Interrupt::$rtc); } } - - /// 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; - } } + impl TimerQueueBackend for $backend_name { + type Ticks = u64; - 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 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<32_768>; - type Duration = fugit::TimerDurationU64<32_768>; - - fn now() -> Self::Instant { + fn now() -> Self::Ticks { let rtc = unsafe { &*$rtc::PTR }; - Self::Instant::from_ticks(calculate_now( + calculate_now( || $overflow.load(Ordering::Relaxed), || TimerValueU24(rtc.counter.read().bits()) - )) + ) } fn on_interrupt() { @@ -243,28 +257,35 @@ macro_rules! make_rtc { } } - fn enable_timer() {} - - fn disable_timer() {} - - fn set_compare(mut instant: Self::Instant) { + fn set_compare(mut instant: Self::Ticks) { let rtc = unsafe { &*$rtc::PTR }; + const MAX: u64 = 0xff_ffff; + // Disable interrupts because this section is timing critical. // We rely on the fact that this entire section runs within one // RTC clock tick. (which it will do easily if it doesn't get // interrupted) critical_section::with(|_|{ let now = Self::now(); - if let Some(diff) = instant.checked_duration_since(now) { + // wrapping_sub deals with the u64 overflow corner case + let diff = instant.wrapping_sub(now); + let val = if diff <= MAX { + // Now we know `instant` whill happen within one `MAX` time duration. + // Errata: Timer interrupts don't fire if they are scheduled less than // two ticks in the future. Make it three, because the timer could // tick right now. - if diff.ticks() < 3 { - instant = Self::Instant::from_ticks(now.ticks().wrapping_add(3)); + if diff < 3 { + instant = now.wrapping_add(3); } - unsafe { rtc.cc[0].write(|w| w.bits(instant.ticks() as u32 & 0xff_ffff)) }; - } + + (instant & MAX) as u32 + } else { + 0 + }; + + unsafe { rtc.cc[0].write(|w| w.bits(val)) }; }); } @@ -274,13 +295,17 @@ macro_rules! make_rtc { } fn pend_interrupt() { - pac::NVIC::pend(Interrupt::$rtc); + pac::NVIC::pend(pac::Interrupt::$rtc); + } + + fn timer_queue() -> &'static TimerQueue<Self> { + &$tq } } }; } -make_rtc!(Rtc0, RTC0, RTC0_OVERFLOWS, RTC0_TQ); -make_rtc!(Rtc1, RTC1, RTC1_OVERFLOWS, RTC1_TQ); +make_rtc!(Rtc0Backend, RTC0, RTC0_OVERFLOWS, RTC0_TQ); +make_rtc!(Rtc1Backend, RTC1, RTC1_OVERFLOWS, RTC1_TQ); #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] -make_rtc!(Rtc2, RTC2, RTC2_OVERFLOWS, RTC2_TQ, doc: (any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))); +make_rtc!(Rtc2Backend, RTC2, RTC2_OVERFLOWS, RTC2_TQ, doc: (any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))); 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"))); |
