diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-07-12 15:46:00 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-07-12 15:46:00 +0000 |
| commit | 132327a40d7d0f1f270d73178feb8653bd0aab49 (patch) | |
| tree | fa0690e8c8c8a1d626423d2b9d7b9d41bb1ea235 | |
| parent | a615a70edabb8fc44abedb9a317a203b0e6491a5 (diff) | |
| parent | ff2daaff679ab79c856164d19b1bd15c7526991f (diff) | |
Merge pull request #1642 from henrikberg/rtc_rp_hb
RP2040 Rtc update with example
| -rw-r--r-- | embassy-rp/src/clocks.rs | 2 | ||||
| -rw-r--r-- | embassy-rp/src/rtc/datetime_no_deps.rs | 1 | ||||
| -rw-r--r-- | embassy-rp/src/rtc/mod.rs | 50 | ||||
| -rw-r--r-- | embassy-rp/src/watchdog.rs | 32 | ||||
| -rw-r--r-- | examples/rp/src/bin/rtc.rs | 44 |
5 files changed, 118 insertions, 11 deletions
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) { | |||
| 308 | // - QSPI (we're using it to run this code!) | 308 | // - QSPI (we're using it to run this code!) |
| 309 | // - PLLs (it may be suicide if that's what's clocking us) | 309 | // - PLLs (it may be suicide if that's what's clocking us) |
| 310 | // - USB, SYSCFG (breaks usb-to-swd on core1) | 310 | // - USB, SYSCFG (breaks usb-to-swd on core1) |
| 311 | // - RTC (else there would be no more time...) | ||
| 311 | let mut peris = reset::ALL_PERIPHERALS; | 312 | let mut peris = reset::ALL_PERIPHERALS; |
| 312 | peris.set_io_qspi(false); | 313 | peris.set_io_qspi(false); |
| 313 | // peris.set_io_bank0(false); // might be suicide if we're clocked from gpin | 314 | // 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) { | |||
| 317 | // TODO investigate if usb should be unreset here | 318 | // TODO investigate if usb should be unreset here |
| 318 | peris.set_usbctrl(false); | 319 | peris.set_usbctrl(false); |
| 319 | peris.set_syscfg(false); | 320 | peris.set_syscfg(false); |
| 321 | peris.set_rtc(false); | ||
| 320 | reset::reset(peris); | 322 | reset::reset(peris); |
| 321 | 323 | ||
| 322 | // Disable resus that may be enabled from previous software | 324 | // 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 { | |||
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | /// Structure containing date and time information | 27 | /// Structure containing date and time information |
| 28 | #[derive(Clone, Debug)] | ||
| 28 | pub struct DateTime { | 29 | pub struct DateTime { |
| 29 | /// 0..4095 | 30 | /// 0..4095 |
| 30 | pub year: u16, | 31 | 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}; | |||
| 12 | use crate::clocks::clk_rtc_freq; | 12 | use crate::clocks::clk_rtc_freq; |
| 13 | 13 | ||
| 14 | /// A reference to the real time clock of the system | 14 | /// A reference to the real time clock of the system |
| 15 | pub struct RealTimeClock<'d, T: Instance> { | 15 | pub struct Rtc<'d, T: Instance> { |
| 16 | inner: PeripheralRef<'d, T>, | 16 | inner: PeripheralRef<'d, T>, |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | impl<'d, T: Instance> RealTimeClock<'d, T> { | 19 | impl<'d, T: Instance> Rtc<'d, T> { |
| 20 | /// Create a new instance of the real time clock, with the given date as an initial value. | 20 | /// Create a new instance of the real time clock, with the given date as an initial value. |
| 21 | /// | 21 | /// |
| 22 | /// # Errors | 22 | /// # Errors |
| 23 | /// | 23 | /// |
| 24 | /// Will return `RtcError::InvalidDateTime` if the datetime is not a valid range. | 24 | /// Will return `RtcError::InvalidDateTime` if the datetime is not a valid range. |
| 25 | pub fn new(inner: impl Peripheral<P = T> + 'd, initial_date: DateTime) -> Result<Self, RtcError> { | 25 | pub fn new(inner: impl Peripheral<P = T> + 'd) -> Self { |
| 26 | into_ref!(inner); | 26 | into_ref!(inner); |
| 27 | 27 | ||
| 28 | // Set the RTC divider | 28 | // Set the RTC divider |
| 29 | inner.regs().clkdiv_m1().write(|w| w.set_clkdiv_m1(clk_rtc_freq() - 1)); | 29 | inner.regs().clkdiv_m1().write(|w| w.set_clkdiv_m1(clk_rtc_freq() - 1)); |
| 30 | 30 | ||
| 31 | let mut result = Self { inner }; | 31 | let result = Self { inner }; |
| 32 | result.set_leap_year_check(true); // should be on by default, make sure this is the case. | 32 | result |
| 33 | result.set_datetime(initial_date)?; | ||
| 34 | Ok(result) | ||
| 35 | } | 33 | } |
| 36 | 34 | ||
| 37 | /// 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. | 35 | /// 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> { | |||
| 43 | }); | 41 | }); |
| 44 | } | 42 | } |
| 45 | 43 | ||
| 46 | /// Checks to see if this RealTimeClock is running | 44 | /// Set the time from internal format |
| 45 | pub fn restore(&mut self, ymd: rp_pac::rtc::regs::Rtc1, hms: rp_pac::rtc::regs::Rtc0) { | ||
| 46 | // disable RTC while we configure it | ||
| 47 | self.inner.regs().ctrl().modify(|w| w.set_rtc_enable(false)); | ||
| 48 | while self.inner.regs().ctrl().read().rtc_active() { | ||
| 49 | core::hint::spin_loop(); | ||
| 50 | } | ||
| 51 | |||
| 52 | self.inner.regs().setup_0().write(|w| { | ||
| 53 | *w = rp_pac::rtc::regs::Setup0(ymd.0); | ||
| 54 | }); | ||
| 55 | self.inner.regs().setup_1().write(|w| { | ||
| 56 | *w = rp_pac::rtc::regs::Setup1(hms.0); | ||
| 57 | }); | ||
| 58 | |||
| 59 | // Load the new datetime and re-enable RTC | ||
| 60 | self.inner.regs().ctrl().write(|w| w.set_load(true)); | ||
| 61 | self.inner.regs().ctrl().write(|w| w.set_rtc_enable(true)); | ||
| 62 | while !self.inner.regs().ctrl().read().rtc_active() { | ||
| 63 | core::hint::spin_loop(); | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | /// Get the time in internal format | ||
| 68 | pub fn save(&mut self) -> (rp_pac::rtc::regs::Rtc1, rp_pac::rtc::regs::Rtc0) { | ||
| 69 | let rtc_0: rp_pac::rtc::regs::Rtc0 = self.inner.regs().rtc_0().read(); | ||
| 70 | let rtc_1 = self.inner.regs().rtc_1().read(); | ||
| 71 | (rtc_1, rtc_0) | ||
| 72 | } | ||
| 73 | |||
| 74 | /// Checks to see if this Rtc is running | ||
| 47 | pub fn is_running(&self) -> bool { | 75 | pub fn is_running(&self) -> bool { |
| 48 | self.inner.regs().ctrl().read().rtc_active() | 76 | self.inner.regs().ctrl().read().rtc_active() |
| 49 | } | 77 | } |
| @@ -113,8 +141,8 @@ impl<'d, T: Instance> RealTimeClock<'d, T> { | |||
| 113 | /// # fn main() { } | 141 | /// # fn main() { } |
| 114 | /// # #[cfg(not(feature = "chrono"))] | 142 | /// # #[cfg(not(feature = "chrono"))] |
| 115 | /// # fn main() { | 143 | /// # fn main() { |
| 116 | /// # use embassy_rp::rtc::{RealTimeClock, DateTimeFilter}; | 144 | /// # use embassy_rp::rtc::{Rtc, DateTimeFilter}; |
| 117 | /// # let mut real_time_clock: RealTimeClock<embassy_rp::peripherals::RTC> = unsafe { core::mem::zeroed() }; | 145 | /// # let mut real_time_clock: Rtc<embassy_rp::peripherals::RTC> = unsafe { core::mem::zeroed() }; |
| 118 | /// let now = real_time_clock.now().unwrap(); | 146 | /// let now = real_time_clock.now().unwrap(); |
| 119 | /// real_time_clock.schedule_alarm( | 147 | /// real_time_clock.schedule_alarm( |
| 120 | /// DateTimeFilter::default() | 148 | /// DateTimeFilter::default() |
| @@ -150,7 +178,7 @@ impl<'d, T: Instance> RealTimeClock<'d, T> { | |||
| 150 | } | 178 | } |
| 151 | } | 179 | } |
| 152 | 180 | ||
| 153 | /// Errors that can occur on methods on [RealTimeClock] | 181 | /// Errors that can occur on methods on [Rtc] |
| 154 | #[derive(Clone, Debug, PartialEq, Eq)] | 182 | #[derive(Clone, Debug, PartialEq, Eq)] |
| 155 | pub enum RtcError { | 183 | pub enum RtcError { |
| 156 | /// An invalid DateTime was given or stored on the hardware. | 184 | /// 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 { | |||
| 107 | w.set_trigger(true); | 107 | w.set_trigger(true); |
| 108 | }) | 108 | }) |
| 109 | } | 109 | } |
| 110 | |||
| 111 | /// Store data in scratch register | ||
| 112 | pub fn set_scratch(&mut self, index: usize, value: u32) { | ||
| 113 | let watchdog = pac::WATCHDOG; | ||
| 114 | match index { | ||
| 115 | 0 => watchdog.scratch0().write(|w| *w = value), | ||
| 116 | 1 => watchdog.scratch1().write(|w| *w = value), | ||
| 117 | 2 => watchdog.scratch2().write(|w| *w = value), | ||
| 118 | 3 => watchdog.scratch3().write(|w| *w = value), | ||
| 119 | 4 => watchdog.scratch4().write(|w| *w = value), | ||
| 120 | 5 => watchdog.scratch5().write(|w| *w = value), | ||
| 121 | 6 => watchdog.scratch6().write(|w| *w = value), | ||
| 122 | 7 => watchdog.scratch7().write(|w| *w = value), | ||
| 123 | _ => panic!("Invalid watchdog scratch index"), | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | /// Read data from scratch register | ||
| 128 | pub fn get_scratch(&mut self, index: usize) -> u32 { | ||
| 129 | let watchdog = pac::WATCHDOG; | ||
| 130 | match index { | ||
| 131 | 0 => watchdog.scratch0().read(), | ||
| 132 | 1 => watchdog.scratch1().read(), | ||
| 133 | 2 => watchdog.scratch2().read(), | ||
| 134 | 3 => watchdog.scratch3().read(), | ||
| 135 | 4 => watchdog.scratch4().read(), | ||
| 136 | 5 => watchdog.scratch5().read(), | ||
| 137 | 6 => watchdog.scratch6().read(), | ||
| 138 | 7 => watchdog.scratch7().read(), | ||
| 139 | _ => panic!("Invalid watchdog scratch index"), | ||
| 140 | } | ||
| 141 | } | ||
| 110 | } | 142 | } |
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 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_rp::rtc::{DateTime, DayOfWeek, Rtc}; | ||
| 8 | use embassy_time::{Duration, Timer}; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | #[embassy_executor::main] | ||
| 12 | async fn main(_spawner: Spawner) { | ||
| 13 | let p = embassy_rp::init(Default::default()); | ||
| 14 | info!("Wait for 20s"); | ||
| 15 | |||
| 16 | let mut rtc = Rtc::new(p.RTC); | ||
| 17 | |||
| 18 | if !rtc.is_running() { | ||
| 19 | info!("Start RTC"); | ||
| 20 | let now = DateTime { | ||
| 21 | year: 2000, | ||
| 22 | month: 1, | ||
| 23 | day: 1, | ||
| 24 | day_of_week: DayOfWeek::Saturday, | ||
| 25 | hour: 0, | ||
| 26 | minute: 0, | ||
| 27 | second: 0, | ||
| 28 | }; | ||
| 29 | rtc.set_datetime(now).unwrap(); | ||
| 30 | } | ||
| 31 | |||
| 32 | Timer::after(Duration::from_millis(20000)).await; | ||
| 33 | |||
| 34 | if let Ok(dt) = rtc.now() { | ||
| 35 | info!( | ||
| 36 | "Now: {}-{:02}-{:02} {}:{:02}:{:02}", | ||
| 37 | dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, | ||
| 38 | ); | ||
| 39 | } | ||
| 40 | |||
| 41 | info!("Reboot."); | ||
| 42 | Timer::after(Duration::from_millis(200)).await; | ||
| 43 | cortex_m::peripheral::SCB::sys_reset(); | ||
| 44 | } | ||
