aboutsummaryrefslogtreecommitdiff
path: root/rtic-monotonics
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2023-04-04 20:03:58 +0000
committerGitHub <noreply@github.com>2023-04-04 20:03:58 +0000
commit72ae46083e64acc012c6b85d3ef7a115657a01e3 (patch)
tree024dbdb94cb5537312c5c34f121257265c165bea /rtic-monotonics
parent064cf19265f72d7f01e0847c545e6250391a2172 (diff)
parentaeec8bd41bdf3d57098902407ec320f59365641a (diff)
Merge #721
721: Added nRF monotonics r=perlindgren a=korken89 Testing completed Co-authored-by: Emil Fresk <emil.fresk@gmail.com>
Diffstat (limited to 'rtic-monotonics')
-rw-r--r--rtic-monotonics/CHANGELOG.md1
-rw-r--r--rtic-monotonics/Cargo.toml25
-rw-r--r--rtic-monotonics/src/lib.rs48
-rw-r--r--rtic-monotonics/src/nrf.rs4
-rw-r--r--rtic-monotonics/src/nrf/rtc.rs241
-rw-r--r--rtic-monotonics/src/nrf/timer.rs268
-rw-r--r--rtic-monotonics/src/rp2040.rs31
-rw-r--r--rtic-monotonics/src/systick.rs26
8 files changed, 641 insertions, 3 deletions
diff --git a/rtic-monotonics/CHANGELOG.md b/rtic-monotonics/CHANGELOG.md
index 816bc24..2a08694 100644
--- a/rtic-monotonics/CHANGELOG.md
+++ b/rtic-monotonics/CHANGELOG.md
@@ -9,6 +9,7 @@ For each category, *Added*, *Changed*, *Fixed* add new entries at the top!
### Added
+- nRF52xxx, nRF9160, nRF5340 Timer and RTC monotonics
- Interrupt tokens for `Systick` and `rp2040` to make sure an interrupt handler exists
### Changed
diff --git a/rtic-monotonics/Cargo.toml b/rtic-monotonics/Cargo.toml
index c961c05..728e171 100644
--- a/rtic-monotonics/Cargo.toml
+++ b/rtic-monotonics/Cargo.toml
@@ -23,8 +23,21 @@ fugit = { version = "0.3.6" }
atomic-polyfill = "1"
cfg-if = "1.0.0"
cortex-m = { version = "0.7.6", optional = true }
+critical-section = { version = "1", optional = true }
+
+# RP2040
rp2040-pac = { version = ">=0.2.0,<0.5", optional = true }
+# nRF52
+nrf52810-pac = { version = "0.12.2", optional = true }
+nrf52811-pac = { version = "0.12.2", optional = true }
+nrf52832-pac = { version = "0.12.2", optional = true }
+nrf52833-pac = { version = "0.12.2", optional = true }
+nrf52840-pac = { version = "0.12.2", optional = true }
+nrf5340-app-pac = { version = "0.12.2", optional = true }
+nrf5340-net-pac = { version = "0.12.2", optional = true }
+nrf9160-pac = { version = "0.12.2", optional = true }
+
[features]
default = []
defmt = ["fugit/defmt"]
@@ -35,4 +48,14 @@ systick-100hz = []
systick-10khz = []
# Timer peripheral on the RP2040
-rp2040 = ["dep:rp2040-pac"]
+rp2040 = ["dep:cortex-m", "dep:rp2040-pac"]
+
+# nRF Timers and RTC
+nrf52810 = ["dep:cortex-m", "dep:nrf52810-pac", "dep:critical-section"]
+nrf52811 = ["dep:cortex-m", "dep:nrf52811-pac", "dep:critical-section"]
+nrf52832 = ["dep:cortex-m", "dep:nrf52832-pac", "dep:critical-section"]
+nrf52833 = ["dep:cortex-m", "dep:nrf52833-pac", "dep:critical-section"]
+nrf52840 = ["dep:cortex-m", "dep:nrf52840-pac", "dep:critical-section"]
+nrf5340-app = ["dep:cortex-m", "dep:nrf5340-app-pac", "dep:critical-section"]
+nrf5340-net = ["dep:cortex-m", "dep:nrf5340-net-pac", "dep:critical-section"]
+nrf9160 = ["dep:cortex-m", "dep:nrf9160-pac", "dep:critical-section"]
diff --git a/rtic-monotonics/src/lib.rs b/rtic-monotonics/src/lib.rs
index 6143fd0..04ce4e2 100644
--- a/rtic-monotonics/src/lib.rs
+++ b/rtic-monotonics/src/lib.rs
@@ -14,6 +14,54 @@ pub mod systick;
#[cfg(feature = "rp2040")]
pub mod rp2040;
+#[cfg(any(
+ feature = "nrf52810",
+ feature = "nrf52811",
+ feature = "nrf52832",
+ feature = "nrf52833",
+ feature = "nrf52840",
+ feature = "nrf5340-app",
+ feature = "nrf5340-net",
+ feature = "nrf9160",
+))]
+pub mod nrf;
+
+#[allow(dead_code)]
+pub(crate) const fn cortex_logical2hw(logical: u8, nvic_prio_bits: u8) -> u8 {
+ ((1 << nvic_prio_bits) - logical) << (8 - nvic_prio_bits)
+}
+
+#[cfg(any(
+ feature = "rp2040",
+ feature = "nrf52810",
+ feature = "nrf52811",
+ feature = "nrf52832",
+ feature = "nrf52833",
+ feature = "nrf52840",
+ feature = "nrf5340-app",
+ feature = "nrf5340-net",
+ feature = "nrf9160",
+))]
+pub(crate) unsafe fn set_monotonic_prio(
+ prio_bits: u8,
+ interrupt: impl cortex_m::interrupt::InterruptNumber,
+) {
+ extern "C" {
+ static RTIC_ASYNC_MAX_LOGICAL_PRIO: u8;
+ }
+
+ let max_prio = RTIC_ASYNC_MAX_LOGICAL_PRIO.max(1).min(1 << prio_bits);
+
+ let hw_prio = crate::cortex_logical2hw(max_prio, prio_bits);
+
+ // We take ownership of the entire IRQ and all settings to it, we only change settings
+ // for the IRQ we control.
+ // This will also compile-error in case the NVIC changes in size.
+ let mut nvic: cortex_m::peripheral::NVIC = core::mem::transmute(());
+
+ nvic.set_priority(interrupt, hw_prio);
+}
+
/// This marker is implemented on an interrupt token to enforce that the right tokens
/// are given to the correct monotonic implementation.
///
diff --git a/rtic-monotonics/src/nrf.rs b/rtic-monotonics/src/nrf.rs
new file mode 100644
index 0000000..0f6b973
--- /dev/null
+++ b/rtic-monotonics/src/nrf.rs
@@ -0,0 +1,4 @@
+//! Monotonic implementations for the nRF series of MCUs.
+
+pub mod rtc;
+pub mod timer;
diff --git a/rtic-monotonics/src/nrf/rtc.rs b/rtic-monotonics/src/nrf/rtc.rs
new file mode 100644
index 0000000..03610c0
--- /dev/null
+++ b/rtic-monotonics/src/nrf/rtc.rs
@@ -0,0 +1,241 @@
+//! RTIC Monotonic impl for the nRF RTCs.
+//!
+//! # Example
+//!
+//! ```
+//! use rtic_monotonics::nrf::rtc::*;
+//!
+//! 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);
+//! }
+//!
+//! async fn usage() {
+//! loop {
+//! // Use the monotonic
+//! Rtc0::delay(100.millis()).await;
+//! }
+//! }
+//! ```
+
+#[cfg(feature = "nrf52810")]
+use nrf52810_pac::{self as pac, Interrupt, RTC0, RTC1};
+#[cfg(feature = "nrf52811")]
+use nrf52811_pac::{self as pac, Interrupt, RTC0, RTC1};
+#[cfg(feature = "nrf52832")]
+use nrf52832_pac::{self as pac, Interrupt, RTC0, RTC1, RTC2};
+#[cfg(feature = "nrf52833")]
+use nrf52833_pac::{self as pac, Interrupt, RTC0, RTC1, RTC2};
+#[cfg(feature = "nrf52840")]
+use nrf52840_pac::{self as pac, Interrupt, RTC0, RTC1, RTC2};
+#[cfg(feature = "nrf5340-app")]
+use nrf5340_app_pac::{self as pac, Interrupt, 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};
+#[cfg(feature = "nrf9160")]
+use nrf9160_pac::{self as pac, Interrupt, RTC0_NS as RTC0, RTC1_NS as RTC1};
+
+use super::super::Monotonic;
+pub use super::super::{TimeoutError, TimerQueue};
+use atomic_polyfill::{AtomicU32, Ordering};
+use core::future::Future;
+pub use fugit::{self, ExtU64};
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! __internal_create_nrf_rtc_interrupt {
+ ($mono_timer:ident, $rtc:ident, $rtc_token:ident) => {{
+ #[no_mangle]
+ #[allow(non_snake_case)]
+ unsafe extern "C" fn $rtc() {
+ $crate::nrf::rtc::$mono_timer::__tq().on_monotonic_interrupt();
+ }
+
+ pub struct $rtc_token;
+
+ unsafe impl $crate::InterruptToken<$crate::nrf::rtc::$mono_timer> for $rtc_token {}
+
+ $rtc_token
+ }};
+}
+
+/// Register the Rtc0 interrupt for the monotonic.
+#[macro_export]
+macro_rules! create_nrf_rtc0_monotonic_token {
+ () => {{
+ $crate::__internal_create_nrf_rtc_interrupt!(Rtc0, RTC0, Rtc0Token)
+ }};
+}
+
+/// Register the Rtc1 interrupt for the monotonic.
+#[macro_export]
+macro_rules! create_nrf_rtc1_monotonic_token {
+ () => {{
+ $crate::__internal_create_nrf_rtc_interrupt!(Rtc1, RTC1, Rtc1Token)
+ }};
+}
+
+/// Register the Rtc2 interrupt for the monotonic.
+#[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! make_rtc {
+ ($mono_name:ident, $rtc:ident, $overflow:ident, $tq:ident) => {
+ /// Monotonic timer queue implementation.
+ pub struct $mono_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>) {
+ unsafe { rtc.prescaler.write(|w| w.bits(0)) };
+ rtc.intenset.write(|w| w.compare0().set().ovrflw().set());
+ rtc.evtenset.write(|w| w.compare0().set().ovrflw().set());
+
+ rtc.tasks_clear.write(|w| unsafe { w.bits(1) });
+ rtc.tasks_start.write(|w| unsafe { w.bits(1) });
+
+ $tq.initialize(Self {});
+
+ // SAFETY: We take full ownership of the peripheral and interrupt vector,
+ // 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);
+ }
+ }
+
+ /// 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;
+ }
+
+ #[inline(always)]
+ fn is_overflow() -> bool {
+ let rtc = unsafe { &*$rtc::PTR };
+ rtc.events_ovrflw.read().bits() == 1
+ }
+ }
+
+ #[cfg(feature = "embedded-hal-async")]
+ impl embedded_hal_async::delay::DelayUs for $mono_name {
+ type Error = core::convert::Infallible;
+
+ #[inline]
+ async fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> {
+ $tq.delay((us as u64).micros()).await;
+ Ok(())
+ }
+
+ #[inline]
+ async fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> {
+ $tq.delay((ms as u64).millis()).await;
+ Ok(())
+ }
+ }
+
+ impl Monotonic for $mono_name {
+ const ZERO: Self::Instant = Self::Instant::from_ticks(0);
+
+ type Instant = fugit::TimerInstantU64<32_768>;
+ type Duration = fugit::TimerDurationU64<32_768>;
+
+ fn now() -> Self::Instant {
+ // In a critical section to not get a race between overflow updates and reading it
+ // and the flag here.
+ critical_section::with(|_| {
+ let rtc = unsafe { &*$rtc::PTR };
+ let cnt = rtc.counter.read().bits() as u64;
+ let ovf = if Self::is_overflow() {
+ $overflow.load(Ordering::Relaxed) + 1
+ } else {
+ $overflow.load(Ordering::Relaxed)
+ } as u64;
+
+ Self::Instant::from_ticks((ovf << 24) | cnt)
+ })
+ }
+
+ fn on_interrupt() {
+ let rtc = unsafe { &*$rtc::PTR };
+ if Self::is_overflow() {
+ $overflow.fetch_add(1, Ordering::SeqCst);
+ rtc.events_ovrflw.write(|w| unsafe { w.bits(0) });
+ }
+ }
+
+ // NOTE: To fix errata for RTC, if the release time is within 4 ticks
+ // we release as the RTC will not generate a compare interrupt...
+ fn should_dequeue_check(release_at: Self::Instant) -> bool {
+ Self::now() + <Self as Monotonic>::Duration::from_ticks(4) >= release_at
+ }
+
+ fn enable_timer() {}
+
+ fn disable_timer() {}
+
+ fn set_compare(instant: Self::Instant) {
+ let rtc = unsafe { &*$rtc::PTR };
+ unsafe { rtc.cc[0].write(|w| w.bits(instant.ticks() as u32 & 0xffffff)) };
+ }
+
+ fn clear_compare_flag() {
+ let rtc = unsafe { &*$rtc::PTR };
+ unsafe { rtc.events_compare[0].write(|w| w.bits(0)) };
+ }
+
+ fn pend_interrupt() {
+ pac::NVIC::pend(Interrupt::$rtc);
+ }
+ }
+ };
+}
+
+make_rtc!(Rtc0, RTC0, RTC0_OVERFLOWS, RTC0_TQ);
+make_rtc!(Rtc1, RTC1, RTC1_OVERFLOWS, RTC1_TQ);
+#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
+make_rtc!(Rtc2, RTC2, RTC2_OVERFLOWS, RTC2_TQ);
diff --git a/rtic-monotonics/src/nrf/timer.rs b/rtic-monotonics/src/nrf/timer.rs
new file mode 100644
index 0000000..db5316f
--- /dev/null
+++ b/rtic-monotonics/src/nrf/timer.rs
@@ -0,0 +1,268 @@
+//! Monotonic impl for the 32-bit timers of the nRF series.
+//!
+//! # Example
+//!
+//! ```
+//! use rtic_monotonics::nrf::timer::*;
+//!
+//! 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);
+//! }
+//!
+//! async fn usage() {
+//! loop {
+//! // Use the monotonic
+//! Timer0::delay(100.millis()).await;
+//! }
+//! }
+//! ```
+
+use super::super::Monotonic;
+pub use super::super::{TimeoutError, TimerQueue};
+use atomic_polyfill::{AtomicU32, Ordering};
+use core::future::Future;
+pub use fugit::{self, ExtU64};
+
+#[cfg(feature = "nrf52810")]
+use nrf52810_pac::{self as pac, Interrupt, TIMER0, TIMER1, TIMER2};
+#[cfg(feature = "nrf52811")]
+use nrf52811_pac::{self as pac, Interrupt, TIMER0, TIMER1, TIMER2};
+#[cfg(feature = "nrf52832")]
+use nrf52832_pac::{self as pac, Interrupt, TIMER0, TIMER1, TIMER2, TIMER3, TIMER4};
+#[cfg(feature = "nrf52833")]
+use nrf52833_pac::{self as pac, Interrupt, TIMER0, TIMER1, TIMER2, TIMER3, TIMER4};
+#[cfg(feature = "nrf52840")]
+use nrf52840_pac::{self as pac, Interrupt, 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,
+};
+#[cfg(feature = "nrf5340-net")]
+use nrf5340_net_pac::{
+ self as pac, Interrupt, 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)]
+#[macro_export]
+macro_rules! __internal_create_nrf_timer_interrupt {
+ ($mono_timer:ident, $timer:ident, $timer_token:ident) => {{
+ #[no_mangle]
+ #[allow(non_snake_case)]
+ unsafe extern "C" fn $timer() {
+ $crate::nrf::timer::$mono_timer::__tq().on_monotonic_interrupt();
+ }
+
+ pub struct $timer_token;
+
+ unsafe impl $crate::InterruptToken<$crate::nrf::timer::$mono_timer> for $timer_token {}
+
+ $timer_token
+ }};
+}
+
+/// Register the Timer0 interrupt for the monotonic.
+#[macro_export]
+macro_rules! create_nrf_timer0_monotonic_token {
+ () => {{
+ $crate::__internal_create_nrf_timer_interrupt!(Timer0, TIMER0, Timer0Token)
+ }};
+}
+
+/// Register the Timer1 interrupt for the monotonic.
+#[macro_export]
+macro_rules! create_nrf_timer1_monotonic_token {
+ () => {{
+ $crate::__internal_create_nrf_timer_interrupt!(Timer1, TIMER1, Timer1Token)
+ }};
+}
+
+/// Register the Timer2 interrupt for the monotonic.
+#[macro_export]
+macro_rules! create_nrf_timer2_monotonic_token {
+ () => {{
+ $crate::__internal_create_nrf_timer_interrupt!(Timer2, TIMER2, Timer2Token)
+ }};
+}
+
+/// Register the Timer3 interrupt for the monotonic.
+#[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)
+ }};
+}
+
+/// Register the Timer4 interrupt for the monotonic.
+#[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! make_timer {
+ ($mono_name:ident, $timer:ident, $overflow:ident, $tq:ident) => {
+ /// Monotonic timer queue implementation.
+ pub struct $mono_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) });
+ timer.bitmode.write(|w| w.bitmode()._32bit());
+ timer
+ .intenset
+ .modify(|_, w| w.compare0().set().compare1().set());
+ timer.cc[1].write(|w| unsafe { w.cc().bits(0) }); // Overflow
+ timer.tasks_clear.write(|w| unsafe { w.bits(1) });
+ timer.tasks_start.write(|w| unsafe { w.bits(1) });
+
+ $tq.initialize(Self {});
+
+ timer.events_compare[0].write(|w| w);
+ timer.events_compare[1].write(|w| w);
+
+ // SAFETY: We take full ownership of the peripheral and interrupt vector,
+ // 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);
+ }
+ }
+
+ /// 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;
+ }
+ }
+
+ #[cfg(feature = "embedded-hal-async")]
+ impl embedded_hal_async::delay::DelayUs for $mono_name {
+ type Error = core::convert::Infallible;
+
+ #[inline]
+ async fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> {
+ $tq.delay((us as u64).micros()).await;
+ Ok(())
+ }
+
+ #[inline]
+ async fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> {
+ $tq.delay((ms as u64).millis()).await;
+ Ok(())
+ }
+ }
+
+ impl Monotonic for $mono_name {
+ const ZERO: Self::Instant = Self::Instant::from_ticks(0);
+
+ type Instant = fugit::TimerInstantU64<1_000_000>;
+ type Duration = fugit::TimerDurationU64<1_000_000>;
+
+ fn now() -> Self::Instant {
+ // In a critical section to not get a race between overflow updates and reading it
+ // and the flag here.
+ critical_section::with(|_| {
+ let timer = unsafe { &*$timer::PTR };
+ timer.tasks_capture[2].write(|w| unsafe { w.bits(1) });
+
+ let unhandled_overflow = if timer.events_compare[1].read().bits() & 1 != 0 {
+ // The overflow has not been handled yet, so add an extra to the read overflow.
+ 1
+ } else {
+ 0
+ };
+
+ Self::Instant::from_ticks(
+ (unhandled_overflow + $overflow.load(Ordering::Relaxed) as u64) << 32
+ | timer.cc[2].read().bits() as u64,
+ )
+ })
+ }
+
+ fn on_interrupt() {
+ let timer = unsafe { &*$timer::PTR };
+
+ // If there is a compare match on channel 1, it is an overflow
+ if timer.events_compare[1].read().bits() & 1 != 0 {
+ timer.events_compare[1].write(|w| w);
+ $overflow.fetch_add(1, Ordering::SeqCst);
+ }
+ }
+
+ fn enable_timer() {}
+
+ fn disable_timer() {}
+
+ fn set_compare(instant: Self::Instant) {
+ let timer = unsafe { &*$timer::PTR };
+ timer.cc[0].write(|w| unsafe { w.cc().bits(instant.ticks() as u32) });
+ }
+
+ fn clear_compare_flag() {
+ let timer = unsafe { &*$timer::PTR };
+ timer.events_compare[0].write(|w| w);
+ }
+
+ fn pend_interrupt() {
+ pac::NVIC::pend(Interrupt::$timer);
+ }
+ }
+ };
+}
+
+make_timer!(Timer0, TIMER0, TIMER0_OVERFLOWS, TIMER0_TQ);
+make_timer!(Timer1, TIMER1, TIMER1_OVERFLOWS, TIMER1_TQ);
+make_timer!(Timer2, TIMER2, TIMER2_OVERFLOWS, TIMER2_TQ);
+#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
+make_timer!(Timer3, TIMER3, TIMER3_OVERFLOWS, TIMER3_TQ);
+#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
+make_timer!(Timer4, TIMER4, TIMER4_OVERFLOWS, TIMER4_TQ);
diff --git a/rtic-monotonics/src/rp2040.rs b/rtic-monotonics/src/rp2040.rs
index 9d2f4f3..c656afc 100644
--- a/rtic-monotonics/src/rp2040.rs
+++ b/rtic-monotonics/src/rp2040.rs
@@ -1,4 +1,28 @@
//! A monotonic implementation for RP2040's Timer peripheral.
+//!
+//! # Example
+//!
+//! ```
+//! use rtic_monotonics::rp2040::*;
+//!
+//! fn init() {
+//! # // This is normally provided by the selected PAC
+//! # let timer = unsafe { core::mem::transmute(()) };
+//! # let mut resets = unsafe { core::mem::transmute(()) };
+//! // Generate the required token
+//! let token = rtic_monotonics::create_rp2040_monotonic_token!();
+//!
+//! // Start the monotonic
+//! Timer::start(timer, &mut resets, token);
+//! }
+//!
+//! async fn usage() {
+//! loop {
+//! // Use the monotonic
+//! Timer::delay(100.millis()).await;
+//! }
+//! }
+//! ```
use super::Monotonic;
pub use super::{TimeoutError, TimerQueue};
@@ -22,7 +46,10 @@ impl Timer {
TIMER_QUEUE.initialize(Self {});
- unsafe { NVIC::unmask(Interrupt::TIMER_IRQ_0) };
+ unsafe {
+ crate::set_monotonic_prio(rp2040_pac::NVIC_PRIO_BITS, Interrupt::TIMER_IRQ_0);
+ NVIC::unmask(Interrupt::TIMER_IRQ_0);
+ }
}
fn timer() -> &'static timer::RegisterBlock {
@@ -41,6 +68,7 @@ impl Timer {
}
/// Timeout at a specific time.
+ #[inline]
pub async fn timeout_at<F: Future>(
instant: <Self as Monotonic>::Instant,
future: F,
@@ -64,6 +92,7 @@ impl Timer {
}
/// Delay to some specific time instant.
+ #[inline]
pub async fn delay_until(instant: <Self as Monotonic>::Instant) {
TIMER_QUEUE.delay_until(instant).await;
}
diff --git a/rtic-monotonics/src/systick.rs b/rtic-monotonics/src/systick.rs
index f4345d4..6a28a11 100644
--- a/rtic-monotonics/src/systick.rs
+++ b/rtic-monotonics/src/systick.rs
@@ -1,4 +1,28 @@
-//! ...
+//! A monotonics based on Cortex-M SysTick. Note that this implementation is inefficient as it
+//! ticks, and generates interrupts, at a constant rate.
+//!
+//! # Example
+//!
+//! ```
+//! use rtic_monotonics::systick::*;
+//!
+//! fn init() {
+//! # // This is normally provided by the selected PAC
+//! # let systick = unsafe { core::mem::transmute(()) };
+//! // Generate the required token
+//! let systick_token = rtic_monotonics::create_systick_token!();
+//!
+//! // Start the monotonic
+//! Systick::start(systick, 12_000_000, systick_token);
+//! }
+//!
+//! async fn usage() {
+//! loop {
+//! // Use the monotonic
+//! Systick::delay(100.millis()).await;
+//! }
+//! }
+//! ```
use super::Monotonic;
pub use super::{TimeoutError, TimerQueue};