diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index ddd61d224..acb21dce5 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -308,6 +308,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { // - QSPI (we're using it to run this code!) // - PLLs (it may be suicide if that's what's clocking us) // - USB, SYSCFG (breaks usb-to-swd on core1) + // - RTC (else there would be no more time...) let mut peris = reset::ALL_PERIPHERALS; peris.set_io_qspi(false); // peris.set_io_bank0(false); // might be suicide if we're clocked from gpin @@ -317,6 +318,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { // TODO investigate if usb should be unreset here peris.set_usbctrl(false); peris.set_syscfg(false); + peris.set_rtc(false); reset::reset(peris); // Disable resus that may be enabled from previous software diff --git a/embassy-rp/src/rtc/datetime_no_deps.rs b/embassy-rp/src/rtc/datetime_no_deps.rs index 92770e984..ea899c339 100644 --- a/embassy-rp/src/rtc/datetime_no_deps.rs +++ b/embassy-rp/src/rtc/datetime_no_deps.rs @@ -25,6 +25,7 @@ pub enum Error { } /// Structure containing date and time information +#[derive(Clone, Debug)] pub struct DateTime { /// 0..4095 pub year: u16, diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs index b18f12fc4..1b33fdf8d 100644 --- a/embassy-rp/src/rtc/mod.rs +++ b/embassy-rp/src/rtc/mod.rs @@ -12,26 +12,24 @@ pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; use crate::clocks::clk_rtc_freq; /// A reference to the real time clock of the system -pub struct RealTimeClock<'d, T: Instance> { +pub struct Rtc<'d, T: Instance> { inner: PeripheralRef<'d, T>, } -impl<'d, T: Instance> RealTimeClock<'d, T> { +impl<'d, T: Instance> Rtc<'d, T> { /// Create a new instance of the real time clock, with the given date as an initial value. /// /// # Errors /// /// Will return `RtcError::InvalidDateTime` if the datetime is not a valid range. - pub fn new(inner: impl Peripheral

+ 'd, initial_date: DateTime) -> Result { + pub fn new(inner: impl Peripheral

+ 'd) -> Self { into_ref!(inner); // Set the RTC divider inner.regs().clkdiv_m1().write(|w| w.set_clkdiv_m1(clk_rtc_freq() - 1)); - let mut result = Self { inner }; - result.set_leap_year_check(true); // should be on by default, make sure this is the case. - result.set_datetime(initial_date)?; - Ok(result) + let result = Self { inner }; + result } /// Enable or disable the leap year check. The rp2040 chip will always add a Feb 29th on every year that is divisable by 4, but this may be incorrect (e.g. on century years). This function allows you to disable this check. @@ -43,7 +41,37 @@ impl<'d, T: Instance> RealTimeClock<'d, T> { }); } - /// Checks to see if this RealTimeClock is running + /// Set the time from internal format + pub fn restore(&mut self, ymd: rp_pac::rtc::regs::Rtc1, hms: rp_pac::rtc::regs::Rtc0) { + // disable RTC while we configure it + self.inner.regs().ctrl().modify(|w| w.set_rtc_enable(false)); + while self.inner.regs().ctrl().read().rtc_active() { + core::hint::spin_loop(); + } + + self.inner.regs().setup_0().write(|w| { + *w = rp_pac::rtc::regs::Setup0(ymd.0); + }); + self.inner.regs().setup_1().write(|w| { + *w = rp_pac::rtc::regs::Setup1(hms.0); + }); + + // Load the new datetime and re-enable RTC + self.inner.regs().ctrl().write(|w| w.set_load(true)); + self.inner.regs().ctrl().write(|w| w.set_rtc_enable(true)); + while !self.inner.regs().ctrl().read().rtc_active() { + core::hint::spin_loop(); + } + } + + /// Get the time in internal format + pub fn save(&mut self) -> (rp_pac::rtc::regs::Rtc1, rp_pac::rtc::regs::Rtc0) { + let rtc_0: rp_pac::rtc::regs::Rtc0 = self.inner.regs().rtc_0().read(); + let rtc_1 = self.inner.regs().rtc_1().read(); + (rtc_1, rtc_0) + } + + /// Checks to see if this Rtc is running pub fn is_running(&self) -> bool { self.inner.regs().ctrl().read().rtc_active() } @@ -113,8 +141,8 @@ impl<'d, T: Instance> RealTimeClock<'d, T> { /// # fn main() { } /// # #[cfg(not(feature = "chrono"))] /// # fn main() { - /// # use embassy_rp::rtc::{RealTimeClock, DateTimeFilter}; - /// # let mut real_time_clock: RealTimeClock = unsafe { core::mem::zeroed() }; + /// # use embassy_rp::rtc::{Rtc, DateTimeFilter}; + /// # let mut real_time_clock: Rtc = unsafe { core::mem::zeroed() }; /// let now = real_time_clock.now().unwrap(); /// real_time_clock.schedule_alarm( /// DateTimeFilter::default() @@ -150,7 +178,7 @@ impl<'d, T: Instance> RealTimeClock<'d, T> { } } -/// Errors that can occur on methods on [RealTimeClock] +/// Errors that can occur on methods on [Rtc] #[derive(Clone, Debug, PartialEq, Eq)] pub enum RtcError { /// An invalid DateTime was given or stored on the hardware. diff --git a/embassy-rp/src/watchdog.rs b/embassy-rp/src/watchdog.rs index d37795cc9..f1e986ec7 100644 --- a/embassy-rp/src/watchdog.rs +++ b/embassy-rp/src/watchdog.rs @@ -107,4 +107,36 @@ impl Watchdog { w.set_trigger(true); }) } + + /// Store data in scratch register + pub fn set_scratch(&mut self, index: usize, value: u32) { + let watchdog = pac::WATCHDOG; + match index { + 0 => watchdog.scratch0().write(|w| *w = value), + 1 => watchdog.scratch1().write(|w| *w = value), + 2 => watchdog.scratch2().write(|w| *w = value), + 3 => watchdog.scratch3().write(|w| *w = value), + 4 => watchdog.scratch4().write(|w| *w = value), + 5 => watchdog.scratch5().write(|w| *w = value), + 6 => watchdog.scratch6().write(|w| *w = value), + 7 => watchdog.scratch7().write(|w| *w = value), + _ => panic!("Invalid watchdog scratch index"), + } + } + + /// Read data from scratch register + pub fn get_scratch(&mut self, index: usize) -> u32 { + let watchdog = pac::WATCHDOG; + match index { + 0 => watchdog.scratch0().read(), + 1 => watchdog.scratch1().read(), + 2 => watchdog.scratch2().read(), + 3 => watchdog.scratch3().read(), + 4 => watchdog.scratch4().read(), + 5 => watchdog.scratch5().read(), + 6 => watchdog.scratch6().read(), + 7 => watchdog.scratch7().read(), + _ => panic!("Invalid watchdog scratch index"), + } + } } diff --git a/examples/rp/src/bin/rtc.rs b/examples/rp/src/bin/rtc.rs new file mode 100644 index 000000000..d569f598f --- /dev/null +++ b/examples/rp/src/bin/rtc.rs @@ -0,0 +1,44 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::rtc::{DateTime, DayOfWeek, Rtc}; +use embassy_time::{Duration, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + info!("Wait for 20s"); + + let mut rtc = Rtc::new(p.RTC); + + if !rtc.is_running() { + info!("Start 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(); + } + + Timer::after(Duration::from_millis(20000)).await; + + if let Ok(dt) = rtc.now() { + info!( + "Now: {}-{:02}-{:02} {}:{:02}:{:02}", + dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, + ); + } + + info!("Reboot."); + Timer::after(Duration::from_millis(200)).await; + cortex_m::peripheral::SCB::sys_reset(); +}