aboutsummaryrefslogtreecommitdiff
path: root/embassy-rp/src
diff options
context:
space:
mode:
author1-rafael-1 <[email protected]>2025-05-16 23:22:34 +0200
committer1-rafael-1 <[email protected]>2025-05-16 23:22:34 +0200
commit1a12942f530df6b3dbd316ca29daf0b9d83ec36d (patch)
tree62cf7a05a4ff6497aab9e176415ca469a6c8046f /embassy-rp/src
parent575eab3c60c0d2098f9e9d2a22429aa174b6b968 (diff)
embassy-rp (rp2040): Rtc wait_for_alarm
Diffstat (limited to 'embassy-rp/src')
-rw-r--r--embassy-rp/src/rtc/datetime_no_deps.rs1
-rw-r--r--embassy-rp/src/rtc/filter.rs3
-rw-r--r--embassy-rp/src/rtc/mod.rs122
3 files changed, 124 insertions, 2 deletions
diff --git a/embassy-rp/src/rtc/datetime_no_deps.rs b/embassy-rp/src/rtc/datetime_no_deps.rs
index 5de00e6b4..77d4a3055 100644
--- a/embassy-rp/src/rtc/datetime_no_deps.rs
+++ b/embassy-rp/src/rtc/datetime_no_deps.rs
@@ -46,6 +46,7 @@ pub struct DateTime {
46/// A day of the week 46/// A day of the week
47#[repr(u8)] 47#[repr(u8)]
48#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] 48#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
49#[cfg_attr(feature = "defmt", derive(defmt::Format))]
49#[allow(missing_docs)] 50#[allow(missing_docs)]
50pub enum DayOfWeek { 51pub enum DayOfWeek {
51 Sunday = 0, 52 Sunday = 0,
diff --git a/embassy-rp/src/rtc/filter.rs b/embassy-rp/src/rtc/filter.rs
index d4a3bab2f..433053613 100644
--- a/embassy-rp/src/rtc/filter.rs
+++ b/embassy-rp/src/rtc/filter.rs
@@ -4,7 +4,8 @@ use crate::pac::rtc::regs::{IrqSetup0, IrqSetup1};
4/// A filter used for [`RealTimeClock::schedule_alarm`]. 4/// A filter used for [`RealTimeClock::schedule_alarm`].
5/// 5///
6/// [`RealTimeClock::schedule_alarm`]: struct.RealTimeClock.html#method.schedule_alarm 6/// [`RealTimeClock::schedule_alarm`]: struct.RealTimeClock.html#method.schedule_alarm
7#[derive(Default)] 7#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
8#[cfg_attr(feature = "defmt", derive(defmt::Format))]
8pub struct DateTimeFilter { 9pub struct DateTimeFilter {
9 /// The year that this alarm should trigger on, `None` if the RTC alarm should not trigger on a year value. 10 /// The year that this alarm should trigger on, `None` if the RTC alarm should not trigger on a year value.
10 pub year: Option<u16>, 11 pub year: Option<u16>,
diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs
index 63cf91d28..7289e46af 100644
--- a/embassy-rp/src/rtc/mod.rs
+++ b/embassy-rp/src/rtc/mod.rs
@@ -1,7 +1,12 @@
1//! RTC driver. 1//! RTC driver.
2mod filter; 2mod filter;
3 3
4use core::future::poll_fn;
5use core::sync::atomic::{compiler_fence, AtomicBool, Ordering};
6use core::task::Poll;
7
4use embassy_hal_internal::{Peri, PeripheralType}; 8use embassy_hal_internal::{Peri, PeripheralType};
9use embassy_sync::waitqueue::AtomicWaker;
5 10
6pub use self::filter::DateTimeFilter; 11pub use self::filter::DateTimeFilter;
7 12
@@ -11,6 +16,13 @@ mod datetime;
11 16
12pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; 17pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError};
13use crate::clocks::clk_rtc_freq; 18use crate::clocks::clk_rtc_freq;
19use crate::interrupt::typelevel::Binding;
20use crate::interrupt::{self, InterruptExt};
21
22// Static waker for the interrupt handler
23static WAKER: AtomicWaker = AtomicWaker::new();
24// Static flag to indicate if an alarm has occurred
25static ALARM_OCCURRED: AtomicBool = AtomicBool::new(false);
14 26
15/// A reference to the real time clock of the system 27/// A reference to the real time clock of the system
16pub struct Rtc<'d, T: Instance> { 28pub struct Rtc<'d, T: Instance> {
@@ -23,10 +35,15 @@ impl<'d, T: Instance> Rtc<'d, T> {
23 /// # Errors 35 /// # Errors
24 /// 36 ///
25 /// Will return `RtcError::InvalidDateTime` if the datetime is not a valid range. 37 /// Will return `RtcError::InvalidDateTime` if the datetime is not a valid range.
26 pub fn new(inner: Peri<'d, T>) -> Self { 38 pub fn new(inner: Peri<'d, T>, _irq: impl Binding<interrupt::typelevel::RTC_IRQ, InterruptHandler>) -> Self {
27 // Set the RTC divider 39 // Set the RTC divider
28 inner.regs().clkdiv_m1().write(|w| w.set_clkdiv_m1(clk_rtc_freq() - 1)); 40 inner.regs().clkdiv_m1().write(|w| w.set_clkdiv_m1(clk_rtc_freq() - 1));
29 41
42 // Setup the IRQ
43 // Clear any pending interrupts from the RTC_IRQ interrupt and enable it, so we do not have unexpected interrupts after initialization
44 interrupt::RTC_IRQ.unpend();
45 unsafe { interrupt::RTC_IRQ.enable() };
46
30 Self { inner } 47 Self { inner }
31 } 48 }
32 49
@@ -174,6 +191,109 @@ impl<'d, T: Instance> Rtc<'d, T> {
174 pub fn clear_interrupt(&mut self) { 191 pub fn clear_interrupt(&mut self) {
175 self.disable_alarm(); 192 self.disable_alarm();
176 } 193 }
194
195 /// Check if an alarm is scheduled.
196 ///
197 /// This function checks if the RTC alarm is currently active. If it is, it returns the alarm configuration
198 /// as a [`DateTimeFilter`]. Otherwise, it returns `None`.
199 pub fn alarm_scheduled(&self) -> Option<DateTimeFilter> {
200 // Check if alarm is active
201 if !self.inner.regs().irq_setup_0().read().match_active() {
202 return None;
203 }
204
205 // Get values from both alarm registers
206 let irq_0 = self.inner.regs().irq_setup_0().read();
207 let irq_1 = self.inner.regs().irq_setup_1().read();
208
209 // Create a DateTimeFilter and populate it based on which fields are enabled
210 let mut filter = DateTimeFilter::default();
211
212 if irq_0.year_ena() {
213 filter.year = Some(irq_0.year());
214 }
215
216 if irq_0.month_ena() {
217 filter.month = Some(irq_0.month());
218 }
219
220 if irq_0.day_ena() {
221 filter.day = Some(irq_0.day());
222 }
223
224 if irq_1.dotw_ena() {
225 // Convert day of week value to DayOfWeek enum
226 let day_of_week = match irq_1.dotw() {
227 0 => DayOfWeek::Sunday,
228 1 => DayOfWeek::Monday,
229 2 => DayOfWeek::Tuesday,
230 3 => DayOfWeek::Wednesday,
231 4 => DayOfWeek::Thursday,
232 5 => DayOfWeek::Friday,
233 6 => DayOfWeek::Saturday,
234 _ => return None, // Invalid day of week
235 };
236 filter.day_of_week = Some(day_of_week);
237 }
238
239 if irq_1.hour_ena() {
240 filter.hour = Some(irq_1.hour());
241 }
242
243 if irq_1.min_ena() {
244 filter.minute = Some(irq_1.min());
245 }
246
247 if irq_1.sec_ena() {
248 filter.second = Some(irq_1.sec());
249 }
250
251 Some(filter)
252 }
253
254 /// Wait for an RTC alarm to trigger.
255 ///
256 /// This function will wait until the RTC alarm is triggered. If the alarm is already triggered, it will return immediately.
257 /// If no alarm is scheduled, it will wait indefinitely until one is scheduled and triggered.
258 pub async fn wait_for_alarm(&mut self) {
259 poll_fn(|cx| {
260 WAKER.register(cx.waker());
261
262 // If the alarm has occured, we will clear the interrupt and return ready
263 if ALARM_OCCURRED.load(Ordering::SeqCst) {
264 // Clear the alarm occurred flag
265 ALARM_OCCURRED.store(false, Ordering::SeqCst);
266
267 // Clear the interrupt and disable the alarm
268 self.clear_interrupt();
269
270 // Return ready
271 compiler_fence(Ordering::SeqCst);
272 return Poll::Ready(());
273 } else {
274 // If the alarm has not occurred, we will return pending
275 return Poll::Pending;
276 }
277 })
278 .await;
279 }
280}
281
282/// Interrupt handler.
283pub struct InterruptHandler {
284 _empty: (),
285}
286
287impl crate::interrupt::typelevel::Handler<crate::interrupt::typelevel::RTC_IRQ> for InterruptHandler {
288 unsafe fn on_interrupt() {
289 // Disable the alarm first thing, to prevent unexpected re-entry
290 let rtc = crate::pac::RTC;
291 rtc.irq_setup_0().modify(|w| w.set_match_ena(false));
292
293 // Set the alarm occurred flag and wake the waker
294 ALARM_OCCURRED.store(true, Ordering::SeqCst);
295 WAKER.wake();
296 }
177} 297}
178 298
179/// Errors that can occur on methods on [Rtc] 299/// Errors that can occur on methods on [Rtc]