Skip to content

Commit

Permalink
feat(rtic-v2-rtc-monotonics): Addresses some issues raised about merg…
Browse files Browse the repository at this point in the history
…ing the PR (#804)

* Adds safety documentation to the `RtcMode` trait methods, and makes all methods safe to call.
* Removes the RTIC-specific prelude and adjusts RTIC items in the crate-level prelude.
* Updates the `rtic` module example to include notes about the `RTIC_ASYNC_MAX_LOGICAL_PRIO` static variable.
  • Loading branch information
Dan Whitman committed Jan 13, 2025
1 parent 42f3ad9 commit 0b8aff5
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 70 deletions.
6 changes: 3 additions & 3 deletions hal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ pub use embedded_hal_async as ehal_async;
#[cfg(feature = "async")]
pub use embedded_io_async;

#[cfg(feature = "rtic")]
pub use rtic_time;

pub mod typelevel;
mod util;

Expand Down Expand Up @@ -91,9 +94,6 @@ pub mod timer_traits;
#[cfg(feature = "dma")]
pub mod dmac;

#[cfg(feature = "rtic")]
pub use rtic_time;

#[doc(hidden)]
mod peripherals;
#[doc(inline)]
Expand Down
5 changes: 4 additions & 1 deletion hal/src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,7 @@ pub use crate::ehal_02::digital::v2::ToggleableOutputPin as _atsamd_hal_embedded
pub use crate::ehal_02::prelude::*;

#[cfg(feature = "rtic")]
pub use crate::rtc::rtic::prelude::*;
pub use rtic_time::Monotonic as _;

#[cfg(feature = "rtic")]
pub use fugit::{ExtU64, ExtU64Ceil};
141 changes: 101 additions & 40 deletions hal/src/rtc/modes.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//! Provides low-level access to the [Real Time Clock (RTC)](https://onlinedocs.microchip.com/oxy/GUID-F5813793-E016-46F5-A9E2-718D8BCED496-en-US-14/GUID-E17D8859-D42B-4B0E-9B81-76168A0C38AC.html) peripheral on ATSAMD chips.
//!
//! The main abstraction is the [`RtcMode`] trait, which exposes
//! static/associated functions to use the RTC in in a particular mode. All functions are marked as [`inline`](https://matklad.github.io/2021/07/09/inline-in-rust.html)
//! so that this should be a zero cost abstraction.
Expand All @@ -9,7 +10,7 @@
//!
//! Abstraction benefits:
//! - Handles all RTC register accesses.
//! - Handles RTC [register synchronization](https://onlinedocs.microchip.com/oxy/GUID-F5813793-E016-46F5-A9E2-718D8BCED496-en-US-14/GUID-ABE2D37F-8125-4279-9955-BC3900046CFF.html)
//! - Handles RTC [register synchronization](https://onlinedocs.microchip.com/oxy/GUID-F5813793-E016-46F5-A9E2-718D8BCED496-en-US-14/GUID-ABE2D37F-8125-4279-9955-BC3900046CFF.html).
//! - Handles ATSAMD chip variations.
//!
//! The idea is that various higher-level users of these abstractions will not
Expand Down Expand Up @@ -46,7 +47,7 @@ pub trait RtcInterrupt {
/// Macro to easily declare an RTC interrupt.
macro_rules! create_rtc_interrupt {
($mode:ident, $name:ident, $bit:ident) => {
/// Type-level variant for the $name interrupt in $mode.
#[doc = concat!("Type-level variant for the ", stringify!($name), " interrupt in ", stringify!($mode))]
pub enum $name {}
impl RtcInterrupt for $name {
#[inline]
Expand Down Expand Up @@ -78,17 +79,59 @@ pub trait RtcMode {
type Count: Copy + PartialEq + Eq;

/// Sets this mode in the CTRL register.
unsafe fn set_mode(rtc: &Rtc);
///
/// # Safety
///
/// This can be called any time but is typically only called once before
/// calling most other methods.
fn set_mode(rtc: &Rtc);

/// Sets a compare value.
unsafe fn set_compare(rtc: &Rtc, number: usize, value: Self::Count);
///
/// # Safety
///
/// Should be called only after setting the RTC mode using
/// [`set_mode`](RtcMode::set_mode).
fn set_compare(rtc: &Rtc, number: usize, value: Self::Count);

/// Retrieves a compare from the register.
///
/// # Safety
///
/// Should be called only after setting the RTC mode using
/// [`set_mode`](RtcMode::set_mode).
fn get_compare(rtc: &Rtc, number: usize) -> Self::Count;

/// Returns the current synced COUNT value.
///
/// # Safety
///
/// Should be called only after setting the RTC mode using
/// [`set_mode`](RtcMode::set_mode).
fn count(rtc: &Rtc) -> Self::Count;

/// Returns whether register syncing is currently happening.
fn sync_busy(rtc: &Rtc) -> bool;
///
/// # Safety
///
/// Can be called any time.
#[inline]
#[hal_macro_helper]
fn sync_busy(rtc: &Rtc) -> bool {
// NOTE: This register and field are the same in all modes.
// SYNC: None
#[hal_cfg(any("rtc-d11", "rtc-d21"))]
return rtc.mode0().status().read().syncbusy().bit_is_set();
// SYNC: None
#[hal_cfg("rtc-d5x")]
return rtc.mode0().syncbusy().read().bits() != 0;
}

/// Resets the RTC, leaving it disabled in MODE0.
///
/// # Safety
///
/// Can be called any time.
#[inline]
#[hal_macro_helper]
fn reset(rtc: &Rtc) {
Expand All @@ -110,6 +153,11 @@ pub trait RtcMode {
}

/// Starts the RTC and does any required initialization for this mode.
///
/// # Safety
///
/// Should be called only after setting the RTC mode using
/// [`set_mode`](RtcMode::set_mode).
#[inline]
#[hal_macro_helper]
fn start_and_initialize(rtc: &Rtc) {
Expand All @@ -131,32 +179,55 @@ pub trait RtcMode {
}

/// Enables an RTC interrupt.
///
/// # Safety
///
/// Should be called only after setting the RTC mode using
/// [`set_mode`](RtcMode::set_mode).
#[inline]
fn enable_interrupt<I: RtcInterrupt>(rtc: &Rtc) {
I::enable(rtc);
}

/// Returns whether an RTC interrupt has been triggered.
///
/// # Safety
///
/// Should be called only after setting the RTC mode using
/// [`set_mode`](RtcMode::set_mode).
#[inline]
fn check_interrupt_flag<I: RtcInterrupt>(rtc: &Rtc) -> bool {
I::check_flag(rtc)
}

/// Clears an RTC interrupt flag so the ISR will not be called again
/// immediately.
///
/// # Safety
///
/// Should be called only after setting the RTC mode using
/// [`set_mode`](RtcMode::set_mode).
#[inline]
fn clear_interrupt_flag<I: RtcInterrupt>(rtc: &Rtc) {
I::clear_flag(rtc);
}

/// Waits for any register syncing to be completed, or returns immediately
/// if no currently syncing.
/// if not currently syncing.
///
/// # Safety
///
/// Can be called any time.
#[inline]
fn sync(rtc: &Rtc) {
while Self::sync_busy(rtc) {}
}

/// Disables the RTC.
///
/// # Safety
///
/// Can be called any time.
#[inline]
#[hal_macro_helper]
fn disable(rtc: &Rtc) {
Expand All @@ -170,6 +241,10 @@ pub trait RtcMode {
}

/// Enables the RTC.
///
/// # Safety
///
/// Can be called any time.
#[inline]
#[hal_macro_helper]
fn enable(rtc: &Rtc) {
Expand All @@ -184,8 +259,14 @@ pub trait RtcMode {

/// Waits until the COUNT register changes.
///
/// Note that this may not necessarily be the next tick due sync delay.
/// Beware that this will wait forever if the RTC is disabled!
/// Note that this may not necessarily be the next tick numerically due sync
/// delay.
///
/// # Safety
///
/// Should be called only after setting the RTC mode using
/// [`set_mode`](RtcMode::set_mode). This will halt forever if called when
/// the RTC is disabled.
#[inline]
fn _wait_for_count_change(rtc: &Rtc) -> Self::Count {
let mut last_count = Self::count(rtc);
Expand All @@ -202,6 +283,7 @@ pub trait RtcMode {
}
}

/// Interface for using the RTC in MODE0 (32-bit COUNT)
pub mod mode0 {
use super::*;

Expand All @@ -211,15 +293,15 @@ pub mod mode0 {
#[hal_cfg("rtc-d5x")]
create_rtc_interrupt!(mode0, Overflow, ovf);

/// The RTC operating in MODE0 (23-bit COUNT)
/// The RTC operating in MODE0 (32-bit COUNT)
pub struct RtcMode0;

impl RtcMode for RtcMode0 {
type Count = u32;

#[inline]
#[hal_macro_helper]
unsafe fn set_mode(rtc: &Rtc) {
fn set_mode(rtc: &Rtc) {
// SYNC: Write
Self::sync(rtc);
// NOTE: This register and field are the same in all modes.
Expand All @@ -230,10 +312,12 @@ pub mod mode0 {
}

#[inline]
unsafe fn set_compare(rtc: &Rtc, number: usize, value: Self::Count) {
fn set_compare(rtc: &Rtc, number: usize, value: Self::Count) {
// SYNC: Write
Self::sync(rtc);
rtc.mode0().comp(number).write(|w| w.comp().bits(value));
unsafe {
rtc.mode0().comp(number).write(|w| w.comp().bits(value));
}
}

#[inline]
Expand All @@ -256,21 +340,10 @@ pub mod mode0 {
Self::sync(rtc);
rtc.mode0().count().read().bits()
}

#[inline]
#[hal_macro_helper]
fn sync_busy(rtc: &Rtc) -> bool {
// SYNC: None
#[hal_cfg(any("rtc-d11", "rtc-d21"))]
return rtc.mode0().status().read().syncbusy().bit_is_set();

// SYNC: None
#[hal_cfg("rtc-d5x")]
return rtc.mode0().syncbusy().read().bits() != 0;
}
}
}

/// Interface for using the RTC in MODE1 (16-bit COUNT)
pub mod mode1 {
use super::*;

Expand All @@ -286,7 +359,7 @@ pub mod mode1 {

#[inline]
#[hal_macro_helper]
unsafe fn set_mode(rtc: &Rtc) {
fn set_mode(rtc: &Rtc) {
// SYNC: Write
Self::sync(rtc);
// NOTE: This register and field are the same in all modes.
Expand All @@ -298,14 +371,14 @@ pub mod mode1 {
// Set the mode 1 period
// SYNC: Write
Self::sync(rtc);
rtc.mode1().per().write(|w| w.bits(0xFFFF));
unsafe { rtc.mode1().per().write(|w| w.bits(0xFFFF)) };
}

#[inline]
unsafe fn set_compare(rtc: &Rtc, number: usize, value: Self::Count) {
fn set_compare(rtc: &Rtc, number: usize, value: Self::Count) {
// SYNC: Write
Self::sync(rtc);
rtc.mode1().comp(number).write(|w| w.comp().bits(value));
unsafe { rtc.mode1().comp(number).write(|w| w.comp().bits(value)) };
}

#[inline]
Expand All @@ -328,17 +401,5 @@ pub mod mode1 {
Self::sync(rtc);
rtc.mode1().count().read().bits()
}

#[inline]
#[hal_macro_helper]
fn sync_busy(rtc: &Rtc) -> bool {
// SYNC: None
#[hal_cfg(any("rtc-d11", "rtc-d21"))]
return rtc.mode1().status().read().syncbusy().bit_is_set();

// SYNC: None
#[hal_cfg("rtc-d5x")]
return rtc.mode1().syncbusy().read().bits() != 0;
}
}
}
10 changes: 4 additions & 6 deletions hal/src/rtc/rtic/backends.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,10 @@ macro_rules! __internal_backend_methods {
// Reset RTC back to initial settings, which disables it and enters mode 0.
<$mode>::reset(&$rtc_pac);

unsafe {
// Set the RTC mode
<$mode>::set_mode(&$rtc_pac);
// Set the RTC mode
<$mode>::set_mode(&$rtc_pac);

$init_compares
}
$init_compares

// Timing critical, make sure we don't get interrupted.
critical_section::with(|_| {
Expand Down Expand Up @@ -305,7 +303,7 @@ macro_rules! __internal_half_period_counting_backend {
<$mode>::count(&rtc).wrapping_sub(1)
};

unsafe { <$mode>::set_compare(&rtc, 0, val) };
<$mode>::set_compare(&rtc, 0, val);
});
}

Expand Down
Loading

0 comments on commit 0b8aff5

Please sign in to comment.