aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-07-12 15:46:00 +0000
committerGitHub <[email protected]>2023-07-12 15:46:00 +0000
commit132327a40d7d0f1f270d73178feb8653bd0aab49 (patch)
treefa0690e8c8c8a1d626423d2b9d7b9d41bb1ea235
parenta615a70edabb8fc44abedb9a317a203b0e6491a5 (diff)
parentff2daaff679ab79c856164d19b1bd15c7526991f (diff)
Merge pull request #1642 from henrikberg/rtc_rp_hb
RP2040 Rtc update with example
-rw-r--r--embassy-rp/src/clocks.rs2
-rw-r--r--embassy-rp/src/rtc/datetime_no_deps.rs1
-rw-r--r--embassy-rp/src/rtc/mod.rs50
-rw-r--r--embassy-rp/src/watchdog.rs32
-rw-r--r--examples/rp/src/bin/rtc.rs44
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)]
28pub struct DateTime { 29pub 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};
12use crate::clocks::clk_rtc_freq; 12use 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
15pub struct RealTimeClock<'d, T: Instance> { 15pub struct Rtc<'d, T: Instance> {
16 inner: PeripheralRef<'d, T>, 16 inner: PeripheralRef<'d, T>,
17} 17}
18 18
19impl<'d, T: Instance> RealTimeClock<'d, T> { 19impl<'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)]
155pub enum RtcError { 183pub 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
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_rp::rtc::{DateTime, DayOfWeek, Rtc};
8use embassy_time::{Duration, Timer};
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async 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}