From ac32f43c3dc915b78e71328855189b8aacfec8c3 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Mon, 15 Sep 2025 21:10:22 +0200 Subject: [PATCH] alarm handling to poll hardware status directly; add ci test --- embassy-rp/src/rtc/mod.rs | 19 ++---- examples/rp/src/bin/rtc_alarm.rs | 12 ++-- tests/rp/Cargo.toml | 6 ++ tests/rp/src/bin/rtc.rs | 113 +++++++++++++++++++++++++++++++ 4 files changed, 129 insertions(+), 21 deletions(-) create mode 100644 tests/rp/src/bin/rtc.rs diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs index 7289e46af..8e6aa66c9 100644 --- a/embassy-rp/src/rtc/mod.rs +++ b/embassy-rp/src/rtc/mod.rs @@ -2,7 +2,7 @@ mod filter; use core::future::poll_fn; -use core::sync::atomic::{compiler_fence, AtomicBool, Ordering}; +use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy_hal_internal::{Peri, PeripheralType}; @@ -21,8 +21,6 @@ use crate::interrupt::{self, InterruptExt}; // Static waker for the interrupt handler static WAKER: AtomicWaker = AtomicWaker::new(); -// Static flag to indicate if an alarm has occurred -static ALARM_OCCURRED: AtomicBool = AtomicBool::new(false); /// A reference to the real time clock of the system pub struct Rtc<'d, T: Instance> { @@ -259,19 +257,15 @@ impl<'d, T: Instance> Rtc<'d, T> { poll_fn(|cx| { WAKER.register(cx.waker()); - // If the alarm has occured, we will clear the interrupt and return ready - if ALARM_OCCURRED.load(Ordering::SeqCst) { - // Clear the alarm occurred flag - ALARM_OCCURRED.store(false, Ordering::SeqCst); - - // Clear the interrupt and disable the alarm + // Check hardware interrupt status directly + if self.inner.regs().ints().read().rtc() { + // Clear the interrupt status and disable the alarm + self.inner.regs().ints().write(|w| w.set_rtc(true)); self.clear_interrupt(); - // Return ready compiler_fence(Ordering::SeqCst); return Poll::Ready(()); } else { - // If the alarm has not occurred, we will return pending return Poll::Pending; } }) @@ -290,8 +284,7 @@ impl crate::interrupt::typelevel::Handler let rtc = crate::pac::RTC; rtc.irq_setup_0().modify(|w| w.set_match_ena(false)); - // Set the alarm occurred flag and wake the waker - ALARM_OCCURRED.store(true, Ordering::SeqCst); + // Wake the waker - interrupt status will be checked directly by polling future WAKER.wake(); } } diff --git a/examples/rp/src/bin/rtc_alarm.rs b/examples/rp/src/bin/rtc_alarm.rs index dccf911e3..e935dbf34 100644 --- a/examples/rp/src/bin/rtc_alarm.rs +++ b/examples/rp/src/bin/rtc_alarm.rs @@ -47,14 +47,10 @@ async fn main(_spawner: Spawner) { ); // See if the alarm is already scheduled, if not, schedule it - match rtc.alarm_scheduled() { - None => { - info!("Scheduling alarm for 30 seconds from now"); - rtc.schedule_alarm(DateTimeFilter::default().second((dt.second + 30) % 60)); - - info!("Alarm scheduled: {}", rtc.alarm_scheduled().unwrap()); - } - Some(_) => {} + if rtc.alarm_scheduled().is_none() { + info!("Scheduling alarm for 30 seconds from now"); + rtc.schedule_alarm(DateTimeFilter::default().second((dt.second + 30) % 60)); + info!("Alarm scheduled: {}", rtc.alarm_scheduled().unwrap()); } } // Alarm triggered diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 809346bed..19461520a 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -64,6 +64,12 @@ name = "float" path = "src/bin/float.rs" required-features = [ "rp2040",] +# RTC is only available on RP2040 +[[bin]] +name = "rtc" +path = "src/bin/rtc.rs" +required-features = [ "rp2040",] + [profile.dev] debug = 2 debug-assertions = true diff --git a/tests/rp/src/bin/rtc.rs b/tests/rp/src/bin/rtc.rs new file mode 100644 index 000000000..8d1d4ee14 --- /dev/null +++ b/tests/rp/src/bin/rtc.rs @@ -0,0 +1,113 @@ +#![no_std] +#![no_main] +#[cfg(feature = "rp2040")] +teleprobe_meta::target!(b"rpi-pico"); + +use defmt::{assert, *}; +use embassy_executor::Spawner; +use embassy_futures::select::{select, Either}; +use embassy_rp::bind_interrupts; +use embassy_rp::rtc::{DateTime, DateTimeFilter, DayOfWeek, Rtc}; +use embassy_time::{Duration, Instant, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +// Bind the RTC interrupt to the handler +bind_interrupts!(struct Irqs { + RTC_IRQ => embassy_rp::rtc::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let mut rtc = Rtc::new(p.RTC, Irqs); + + info!("RTC test started"); + + // Initialize RTC if not running + if !rtc.is_running() { + info!("Starting RTC"); + let now = DateTime { + year: 2000, + month: 1, + day: 1, + day_of_week: DayOfWeek::Saturday, + hour: 0, + minute: 0, + second: 0, + }; + rtc.set_datetime(now).unwrap(); + } + + // Test 1: Basic RTC functionality - read current time + let initial_time = rtc.now().unwrap(); + info!( + "Initial time: {}-{:02}-{:02} {}:{:02}:{:02}", + initial_time.year, + initial_time.month, + initial_time.day, + initial_time.hour, + initial_time.minute, + initial_time.second + ); + + // Test 2: Schedule and wait for alarm + info!("Testing alarm scheduling"); + + // Schedule alarm for 3 seconds from now + let alarm_second = (initial_time.second + 3) % 60; + let alarm_filter = DateTimeFilter::default().second(alarm_second); + + info!("Scheduling alarm for second: {}", alarm_second); + rtc.schedule_alarm(alarm_filter); + + // Verify alarm is scheduled + let scheduled = rtc.alarm_scheduled(); + assert!(scheduled.is_some(), "Alarm should be scheduled"); + info!("Alarm scheduled successfully: {}", scheduled.unwrap()); + + // Wait for alarm with timeout + let alarm_start = Instant::now(); + match select(Timer::after_secs(5), rtc.wait_for_alarm()).await { + Either::First(_) => { + core::panic!("Alarm timeout - alarm should have triggered within 5 seconds"); + } + Either::Second(_) => { + let alarm_duration = Instant::now() - alarm_start; + info!("ALARM TRIGGERED after {:?}", alarm_duration); + + // Verify timing is reasonable (should be around 3 seconds, allow some margin) + assert!( + alarm_duration >= Duration::from_secs(2) && alarm_duration <= Duration::from_secs(4), + "Alarm timing incorrect: {:?}", + alarm_duration + ); + } + } + + // Test 3: Verify RTC is still running and time has advanced + let final_time = rtc.now().unwrap(); + info!( + "Final time: {}-{:02}-{:02} {}:{:02}:{:02}", + final_time.year, final_time.month, final_time.day, final_time.hour, final_time.minute, final_time.second + ); + + // Verify time has advanced (allowing for minute/hour rollover) + let time_diff = if final_time.second >= initial_time.second { + final_time.second - initial_time.second + } else { + 60 - initial_time.second + final_time.second + }; + + assert!(time_diff >= 3, "RTC should have advanced by at least 3 seconds"); + info!("Time advanced by {} seconds", time_diff); + + // Test 4: Verify alarm is no longer scheduled after triggering + let post_alarm_scheduled = rtc.alarm_scheduled(); + assert!( + post_alarm_scheduled.is_none(), + "Alarm should not be scheduled after triggering" + ); + + info!("Test OK"); + cortex_m::asm::bkpt(); +}