Merge pull request #1642 from henrikberg/rtc_rp_hb
RP2040 Rtc update with example
This commit is contained in:
commit
132327a40d
@ -308,6 +308,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
|
|||||||
// - QSPI (we're using it to run this code!)
|
// - QSPI (we're using it to run this code!)
|
||||||
// - PLLs (it may be suicide if that's what's clocking us)
|
// - PLLs (it may be suicide if that's what's clocking us)
|
||||||
// - USB, SYSCFG (breaks usb-to-swd on core1)
|
// - USB, SYSCFG (breaks usb-to-swd on core1)
|
||||||
|
// - RTC (else there would be no more time...)
|
||||||
let mut peris = reset::ALL_PERIPHERALS;
|
let mut peris = reset::ALL_PERIPHERALS;
|
||||||
peris.set_io_qspi(false);
|
peris.set_io_qspi(false);
|
||||||
// peris.set_io_bank0(false); // might be suicide if we're clocked from gpin
|
// 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
|
// TODO investigate if usb should be unreset here
|
||||||
peris.set_usbctrl(false);
|
peris.set_usbctrl(false);
|
||||||
peris.set_syscfg(false);
|
peris.set_syscfg(false);
|
||||||
|
peris.set_rtc(false);
|
||||||
reset::reset(peris);
|
reset::reset(peris);
|
||||||
|
|
||||||
// Disable resus that may be enabled from previous software
|
// Disable resus that may be enabled from previous software
|
||||||
|
@ -25,6 +25,7 @@ pub enum Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Structure containing date and time information
|
/// Structure containing date and time information
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct DateTime {
|
pub struct DateTime {
|
||||||
/// 0..4095
|
/// 0..4095
|
||||||
pub year: u16,
|
pub year: u16,
|
||||||
|
@ -12,26 +12,24 @@ pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError};
|
|||||||
use crate::clocks::clk_rtc_freq;
|
use crate::clocks::clk_rtc_freq;
|
||||||
|
|
||||||
/// A reference to the real time clock of the system
|
/// 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>,
|
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.
|
/// Create a new instance of the real time clock, with the given date as an initial value.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Will return `RtcError::InvalidDateTime` if the datetime is not a valid range.
|
/// Will return `RtcError::InvalidDateTime` if the datetime is not a valid range.
|
||||||
pub fn new(inner: impl Peripheral<P = T> + 'd, initial_date: DateTime) -> Result<Self, RtcError> {
|
pub fn new(inner: impl Peripheral<P = T> + 'd) -> Self {
|
||||||
into_ref!(inner);
|
into_ref!(inner);
|
||||||
|
|
||||||
// Set the RTC divider
|
// Set the RTC divider
|
||||||
inner.regs().clkdiv_m1().write(|w| w.set_clkdiv_m1(clk_rtc_freq() - 1));
|
inner.regs().clkdiv_m1().write(|w| w.set_clkdiv_m1(clk_rtc_freq() - 1));
|
||||||
|
|
||||||
let mut result = Self { inner };
|
let result = Self { inner };
|
||||||
result.set_leap_year_check(true); // should be on by default, make sure this is the case.
|
result
|
||||||
result.set_datetime(initial_date)?;
|
|
||||||
Ok(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.
|
/// 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 {
|
pub fn is_running(&self) -> bool {
|
||||||
self.inner.regs().ctrl().read().rtc_active()
|
self.inner.regs().ctrl().read().rtc_active()
|
||||||
}
|
}
|
||||||
@ -113,8 +141,8 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
|
|||||||
/// # fn main() { }
|
/// # fn main() { }
|
||||||
/// # #[cfg(not(feature = "chrono"))]
|
/// # #[cfg(not(feature = "chrono"))]
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// # use embassy_rp::rtc::{RealTimeClock, DateTimeFilter};
|
/// # use embassy_rp::rtc::{Rtc, DateTimeFilter};
|
||||||
/// # let mut real_time_clock: RealTimeClock<embassy_rp::peripherals::RTC> = unsafe { core::mem::zeroed() };
|
/// # let mut real_time_clock: Rtc<embassy_rp::peripherals::RTC> = unsafe { core::mem::zeroed() };
|
||||||
/// let now = real_time_clock.now().unwrap();
|
/// let now = real_time_clock.now().unwrap();
|
||||||
/// real_time_clock.schedule_alarm(
|
/// real_time_clock.schedule_alarm(
|
||||||
/// DateTimeFilter::default()
|
/// 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)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum RtcError {
|
pub enum RtcError {
|
||||||
/// An invalid DateTime was given or stored on the hardware.
|
/// An invalid DateTime was given or stored on the hardware.
|
||||||
|
@ -107,4 +107,36 @@ impl Watchdog {
|
|||||||
w.set_trigger(true);
|
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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
44
examples/rp/src/bin/rtc.rs
Normal file
44
examples/rp/src/bin/rtc.rs
Normal file
@ -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();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user