Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 18 additions & 19 deletions crates.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"boards": {

"atsame54_xpro": {
"tier": 1,
"build": "cargo build --examples --all-features",
Expand Down Expand Up @@ -267,75 +266,75 @@
},
"hal_build_variants": {
"samd11c": {
"features": [ "samd11c", "dma", "rtic", "defmt", "async", "undoc-features" ],
"features": [ "samd11c", "dma", "rtic", "embassy-time", "defmt", "async", "undoc-features" ],
"target": "thumbv6m-none-eabi"
},
"samd11d": {
"features": [ "samd11d", "dma", "rtic", "defmt", "async", "undoc-features" ],
"features": [ "samd11d", "dma", "rtic", "embassy-time", "defmt", "async", "undoc-features" ],
"target": "thumbv6m-none-eabi"
},
"samd21e": {
"features": [ "samd21e", "usb", "dma", "rtic", "defmt", "async", "undoc-features" ],
"features": [ "samd21e", "usb", "dma", "rtic", "embassy-time", "defmt", "async", "undoc-features" ],
"target": "thumbv6m-none-eabi"
},
"samd21el": {
"features": [ "samd21el", "dma", "rtic", "defmt", "async", "undoc-features" ],
"features": [ "samd21el", "dma", "rtic", "embassy-time", "defmt", "async", "undoc-features" ],
"target": "thumbv6m-none-eabi"
},
"samd21g": {
"features": [ "samd21g", "usb", "dma", "rtic", "defmt", "async", "undoc-features" ],
"features": [ "samd21g", "usb", "dma", "rtic", "embassy-time", "defmt", "async", "undoc-features" ],
"target": "thumbv6m-none-eabi"
},
"samd21gl": {
"features": [ "samd21gl", "dma", "rtic", "defmt", "async", "undoc-features" ],
"features": [ "samd21gl", "dma", "rtic", "embassy-time", "defmt", "async", "undoc-features" ],
"target": "thumbv6m-none-eabi"
},
"samd21j": {
"features": [ "samd21j", "usb", "dma", "rtic", "defmt", "async", "undoc-features" ],
"features": [ "samd21j", "usb", "dma", "rtic", "embassy-time", "defmt", "async", "undoc-features" ],
"target": "thumbv6m-none-eabi"
},
"samd51g": {
"features": [ "samd51g", "usb", "dma", "sdmmc", "rtic", "defmt", "async", "undoc-features" ],
"features": [ "samd51g", "usb", "dma", "sdmmc", "rtic", "embassy-time", "defmt", "async", "undoc-features" ],
"target": "thumbv7em-none-eabihf"
},
"samd51j": {
"features": [ "samd51j", "usb", "dma", "sdmmc", "rtic", "defmt", "async", "undoc-features" ],
"features": [ "samd51j", "usb", "dma", "sdmmc", "rtic", "embassy-time", "defmt", "async", "undoc-features" ],
"target": "thumbv7em-none-eabihf"
},
"samd51n": {
"features": [ "samd51n", "usb", "dma", "sdmmc", "rtic", "defmt", "async", "undoc-features" ],
"features": [ "samd51n", "usb", "dma", "sdmmc", "rtic", "embassy-time", "defmt", "async", "undoc-features" ],
"target": "thumbv7em-none-eabihf"
},
"samd51p": {
"features": [ "samd51p", "usb", "dma", "sdmmc", "rtic", "defmt", "async", "undoc-features" ],
"features": [ "samd51p", "usb", "dma", "sdmmc", "rtic", "embassy-time", "defmt", "async", "undoc-features" ],
"target": "thumbv7em-none-eabihf"
},
"same51g": {
"features": [ "same51g", "usb", "dma", "sdmmc", "rtic", "can", "defmt", "async", "undoc-features" ],
"features": [ "same51g", "usb", "dma", "sdmmc", "rtic", "embassy-time", "can", "defmt", "async", "undoc-features" ],
"target": "thumbv7em-none-eabihf"
},
"same51j": {
"features": [ "same51j", "usb", "dma", "sdmmc", "rtic", "can", "defmt", "async", "undoc-features" ],
"features": [ "same51j", "usb", "dma", "sdmmc", "rtic", "embassy-time", "can", "defmt", "async", "undoc-features" ],
"target": "thumbv7em-none-eabihf"
},
"same51n": {
"features": [ "same51n", "usb", "dma", "sdmmc", "rtic", "can", "defmt", "async" , "undoc-features"],
"features": [ "same51n", "usb", "dma", "sdmmc", "rtic", "embassy-time", "can", "defmt", "async", "undoc-features" ],
"target": "thumbv7em-none-eabihf"
},
"same53j": {
"features": [ "same53j", "usb", "dma", "sdmmc", "rtic", "defmt", "async", "undoc-features" ],
"features": [ "same53j", "usb", "dma", "sdmmc", "rtic", "embassy-time", "defmt", "async", "undoc-features" ],
"target": "thumbv7em-none-eabihf"
},
"same53n": {
"features": [ "same53n", "usb", "dma", "sdmmc", "rtic", "defmt", "async", "undoc-features" ],
"features": [ "same53n", "usb", "dma", "sdmmc", "rtic", "embassy-time", "defmt", "async", "undoc-features" ],
"target": "thumbv7em-none-eabihf"
},
"same54n": {
"features": [ "same54n", "usb", "dma", "sdmmc", "rtic", "can", "defmt", "async", "undoc-features" ],
"features": [ "same54n", "usb", "dma", "sdmmc", "rtic", "embassy-time", "can", "defmt", "async", "undoc-features" ],
"target": "thumbv7em-none-eabihf"
},
"same54p": {
"features": [ "same54p", "usb", "dma", "sdmmc", "rtic", "can", "defmt", "async", "undoc-features" ],
"features": [ "same54p", "usb", "dma", "sdmmc", "rtic", "embassy-time", "can", "defmt", "async", "undoc-features" ],
"target": "thumbv7em-none-eabihf"
}
}
Expand Down
4 changes: 4 additions & 0 deletions hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ rtic-monotonic = {version = "1.0", optional = true}
rtic-time = {version = "2.0", optional = true}
usb-device = {version = "0.3.2", optional = true}

embassy-time-driver = { version = "0.2", optional = true, features = ["tick-hz-32_768"] }
embassy-time-queue-utils = { version = "0.3", optional = true }

#===============================================================================
# PACs
#===============================================================================
Expand Down Expand Up @@ -194,6 +197,7 @@ defmt = ["dep:defmt"]
dma = []
max-channels = ["dma"]
rtic = ["rtic-monotonic", "rtic-time", "portable-atomic"]
embassy-time = ["embassy-sync", "embassy-time-driver", "embassy-time-queue-utils"]
sdmmc = ["embedded-sdmmc"]
use_rtt = ["jlink_rtt"]
undoc-features = []
Expand Down
5 changes: 5 additions & 0 deletions hal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ pub use embedded_io_async;
#[cfg(feature = "rtic")]
pub use rtic_time;

// Exposed only so the macro can initialize it
#[cfg(feature = "embassy-time")]
#[doc(hidden)]
pub use embassy_time_driver;

pub mod typelevel;
mod util;

Expand Down
176 changes: 176 additions & 0 deletions hal/src/rtc/embassy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
//! This is a driver for embassy-time
//! It must be instantiated with embassy_time!()
//! which will configure the chip's RTC

use core::cell::RefCell;
use core::task::Waker;

use crate::pac::{Interrupt, NVIC, Rtc};
use crate::rtc::modes::{
RtcMode,
mode0::{Compare0, RtcMode0},
};
use atsamd_hal_macros::hal_cfg;
use critical_section::CriticalSection;
use embassy_sync::blocking_mutex::{Mutex, raw::CriticalSectionRawMutex};
use embassy_time_driver::Driver;
use embassy_time_queue_utils::Queue;

/// Used internally by the embassy time driver.
/// You shouldn't need this
pub struct EmbassyBackend {
queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>,
}

impl EmbassyBackend {
#[allow(clippy::new_without_default)]
pub const fn new() -> Self {
Self {
queue: Mutex::new(RefCell::new(Queue::new())),
}
}

fn set_alarm(&self, _cs: &CriticalSection, at: u64, rtc: &Rtc) -> bool {
// Embassy uses u64::MAX as a "no upcoming interrupt" sentinel
let at = match u32::try_from(at) {
_ if at == u64::MAX => return true,
Ok(at) => at,
Err(_) => return false,
};

if RtcMode0::count(rtc) >= at {
// This is in the past
return false;
}

RtcMode0::set_compare(rtc, 0, at);
// double check that the timestamp is still in the future
if RtcMode0::count(rtc) >= at {
// This is in the past
return false;
}
true
}

pub fn handle_interrupt(&self, rtc: &Rtc, cs: CriticalSection) {
if RtcMode0::check_interrupt_flag::<Compare0>(rtc) {
// Due to synchronization delay, the RTC may be slightly behind
// Assume the current time is the time the interrupt is set for
let now = RtcMode0::get_compare(rtc, 0) as u64;
loop {
let next = self.queue.borrow(cs).borrow_mut().next_expiration(now);
if self.set_alarm(&cs, next, rtc) {
break;
}
}
RtcMode0::clear_interrupt_flag::<Compare0>(rtc);
}
}

/// # Safety
///
/// This enables interrupts, which can break out of critical sections
pub unsafe fn init() {
let rtc = unsafe { Rtc::steal() };

RtcMode0::disable(&rtc);
RtcMode0::reset(&rtc);
RtcMode0::set_mode(&rtc);

RtcMode0::start_and_initialize(&rtc);
RtcMode0::clear_interrupt_flag::<Compare0>(&rtc);
RtcMode0::enable_interrupt::<Compare0>(&rtc);

RtcMode0::enable(&rtc);
unsafe {
cortex_m::interrupt::enable();
let mut nvic: cortex_m::peripheral::NVIC = core::mem::transmute(());
nvic.set_priority(Interrupt::RTC, 1);
NVIC::unmask(Interrupt::RTC);
}
}
}

impl Driver for EmbassyBackend {
fn now(&self) -> u64 {
critical_section::with(|_cs| {
let rtc = unsafe { Rtc::steal() };
RtcMode0::count(&rtc) as u64
})
}

fn schedule_wake(&self, at: u64, waker: &Waker) {
critical_section::with(|cs| {
let rtc = unsafe { Rtc::steal() };
let mut queue = self.queue.borrow(cs).borrow_mut();
if queue.schedule_wake(at, waker) {
loop {
let next = queue.next_expiration(self.now());

// We can only handle one alarm at a time right now
self.set_alarm(&cs, next, &rtc);
}
}
});
}
}

pub trait EmbassyRtcSource {}

#[hal_cfg(any("clock-d11", "clock-d21"))]
mod rtc_src {
impl super::EmbassyRtcSource for crate::clock::RtcClock {}
}

#[hal_cfg("clock-d5x")]
mod rtc_src {
use crate::clock::v2::{osculp32k::OscUlp32kId, rtcosc::RtcOsc, xosc32k::Xosc32kId};
impl super::EmbassyRtcSource for RtcOsc<OscUlp32kId> {}
impl super::EmbassyRtcSource for RtcOsc<Xosc32kId> {}
}

#[allow(unused_imports)]
use rtc_src::*;

/// Create an embassy-time compliant driver
/// This driver should be called outside any function
/// The driver must be started by calling init() on the created struct
/// with an RTC token to indicate proper configuration
/// ```invalid
/// rtc::embassy::embassy_time!(Driver);
///
/// #[embassy_executor::main]
/// async fn main(_s: embassy_executor::Spawner) {
/// let rtc_token = set_up_clock!();
/// /// Safety: called outside a critical section
/// unsafe {
/// Driver::init(rtc_token);
/// }
/// }
/// ```
#[macro_export]
macro_rules! embassy_time {
($name: ident) => {

use $crate::pac::interrupt;
use $crate::{embassy_time_driver, rtc::embassy::{EmbassyBackend, EmbassyRtcSource}};

embassy_time_driver::time_driver_impl!(static DRIVER: EmbassyBackend = EmbassyBackend::new());

#[$crate::pac::interrupt]
fn RTC() {
critical_section::with(|cs| {
let rtc = unsafe { $crate::pac::Rtc::steal() };
DRIVER.handle_interrupt(&rtc, cs)
});
}

pub struct $name;

impl $name {
unsafe fn init<SRC>(_rtc: SRC) where SRC: EmbassyRtcSource {
EmbassyBackend::init();
}
}
}
}
3 changes: 3 additions & 0 deletions hal/src/rtc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ mod modes;
#[cfg(feature = "rtic")]
pub mod rtic;

#[cfg(feature = "embassy-time")]
pub mod embassy;

// SAMx5x imports
#[hal_cfg("rtc-d5x")]
use crate::pac::{Mclk as Pm, rtc::mode0::ctrla::Prescalerselect};
Expand Down
10 changes: 4 additions & 6 deletions hal/src/rtc/modes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ pub trait RtcMode {
///
/// Should be called only after setting the RTC mode using
/// [`set_mode`](RtcMode::set_mode).
#[cfg(feature = "rtic")]
#[cfg(any(feature = "rtic", feature = "embassy-time"))]
fn get_compare(rtc: &Rtc, number: usize) -> Self::Count;

/// Returns the current synced COUNT value.
Expand Down Expand Up @@ -402,7 +402,7 @@ pub mod mode0 {
}

#[inline]
#[cfg(feature = "rtic")]
#[cfg(any(feature = "rtic", feature = "embassy-time"))]
fn get_compare(rtc: &Rtc, number: usize) -> Self::Count {
// SYNC: Write (we just read though)
rtc.mode0().comp(number).read().bits()
Expand Down Expand Up @@ -439,9 +439,7 @@ pub mod mode1 {
use super::*;

create_rtc_interrupt!(mode1, Compare0, cmp0);
#[cfg(feature = "rtic")]
create_rtc_interrupt!(mode1, Compare1, cmp1);
#[cfg(feature = "rtic")]
create_rtc_interrupt!(mode1, Overflow, ovf);

/// The RTC operating in MODE1 (16-bit COUNT)
Expand Down Expand Up @@ -475,7 +473,7 @@ pub mod mode1 {
}

#[inline]
#[cfg(feature = "rtic")]
#[cfg(any(feature = "rtic", feature = "embassy-time"))]
fn get_compare(rtc: &Rtc, number: usize) -> Self::Count {
// SYNC: Write (we just read though)
rtc.mode1().comp(number).read().bits()
Expand Down Expand Up @@ -607,7 +605,7 @@ pub mod mode2 {

#[inline]
#[hal_macro_helper]
#[cfg(feature = "rtic")]
#[cfg(any(feature = "rtic", feature = "embassy-time"))]
fn get_compare(rtc: &Rtc, _number: usize) -> Self::Count {
// SYNC: Write (we just read though)
#[hal_cfg(any("rtc-d11", "rtc-d21"))]
Expand Down
Loading