Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Runtime ISR binding and simple public API docs for RTC #1405

Merged
merged 3 commits into from
Apr 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions esp-hal/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- ESP32-C6: The `gpio::lp_gpio` module has been renamed to `gpio::lp_io` to match the peripheral name (#1397)
- Runtime ISR binding for assist_debug (#1395)
- Runtime ISR binding for software interrupts, software interrupts are split now, interrupt-executor takes the software interrupt to use, interrupt-executor is easier to use (#1398)
- Runtime ISR binding for RTC (#1405)

### Removed

Expand Down
2 changes: 1 addition & 1 deletion esp-hal/src/peripheral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
//! ```
//! ### Accessing peripherals
//! ```no_run
//! let mut rtc = Rtc::new(peripherals.LPWR);
//! let mut rtc = Rtc::new(peripherals.LPWR, None);
//! ```
//! ```no_run
//! let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
Expand Down
86 changes: 62 additions & 24 deletions esp-hal/src/rtc_cntl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@
//! Where the `LP_WDT` interrupt handler is defined as:
//! ```no_run
//! // Handle the corresponding interrupt
//! #[interrupt]
//! fn LP_WDT() {
//! #[handler]
//! fn interrupt_handler() {
//! critical_section::with(|cs| {
//! esp_println::println!("RWDT Interrupt");
//!
Expand Down Expand Up @@ -86,7 +86,9 @@ use crate::peripherals::{LP_TIMER, LP_WDT};
use crate::rtc_cntl::sleep::{RtcSleepConfig, WakeSource, WakeTriggers};
use crate::{
clock::Clock,
interrupt::{self, InterruptHandler},
peripheral::{Peripheral, PeripheralRef},
peripherals::Interrupt,
reset::{SleepSource, WakeupReason},
Cpu,
};
Expand Down Expand Up @@ -187,7 +189,13 @@ pub struct Rtc<'d> {
}

impl<'d> Rtc<'d> {
pub fn new(rtc_cntl: impl Peripheral<P = crate::peripherals::LPWR> + 'd) -> Self {
/// Create a new instance in [crate::Blocking] mode.
///
/// Optionally an interrupt handler can be bound.
pub fn new(
rtc_cntl: impl Peripheral<P = crate::peripherals::LPWR> + 'd,
interrupt: Option<InterruptHandler>,
) -> Self {
rtc::init();
rtc::configure_clock();

Expand All @@ -201,14 +209,35 @@ impl<'d> Rtc<'d> {
#[cfg(any(esp32, esp32s3, esp32c3, esp32c6))]
RtcSleepConfig::base_settings(&this);

if let Some(interrupt) = interrupt {
unsafe {
interrupt::bind_interrupt(
#[cfg(any(esp32c6, esp32h2))]
Interrupt::LP_WDT,
#[cfg(not(any(esp32c6, esp32h2)))]
Interrupt::RTC_CORE,
interrupt.handler(),
);
interrupt::enable(
#[cfg(any(esp32c6, esp32h2))]
Interrupt::LP_WDT,
#[cfg(not(any(esp32c6, esp32h2)))]
Interrupt::RTC_CORE,
interrupt.priority(),
)
.unwrap();
}
}

this
}

/// Return estimated XTAL frequency in MHz.
pub fn estimate_xtal_frequency(&mut self) -> u32 {
RtcClock::estimate_xtal_frequency()
}

/// read the current value of the rtc time registers.
/// Read the current value of the rtc time registers.
pub fn get_time_raw(&self) -> u64 {
#[cfg(not(any(esp32c6, esp32h2)))]
let rtc_cntl = unsafe { &*LPWR::ptr() };
Expand Down Expand Up @@ -247,17 +276,17 @@ impl<'d> Rtc<'d> {
((h as u64) << 32) | (l as u64)
}

/// read the current value of the rtc time registers in microseconds.
/// Read the current value of the rtc time registers in microseconds.
pub fn get_time_us(&self) -> u64 {
self.get_time_raw() * 1_000_000 / RtcClock::get_slow_freq().frequency().to_Hz() as u64
}

/// read the current value of the rtc time registers in milliseconds
/// Read the current value of the rtc time registers in milliseconds.
pub fn get_time_ms(&self) -> u64 {
self.get_time_raw() * 1_000 / RtcClock::get_slow_freq().frequency().to_Hz() as u64
}

/// enter deep sleep and wake with the provided `wake_sources`
/// Enter deep sleep and wake with the provided `wake_sources`.
#[cfg(any(esp32, esp32s3, esp32c3, esp32c6))]
pub fn sleep_deep(
&mut self,
Expand All @@ -269,7 +298,7 @@ impl<'d> Rtc<'d> {
unreachable!();
}

/// enter light sleep and wake with the provided `wake_sources`
/// Enter light sleep and wake with the provided `wake_sources`.
#[cfg(any(esp32, esp32s3, esp32c3, esp32c6))]
pub fn sleep_light(
&mut self,
Expand All @@ -280,8 +309,8 @@ impl<'d> Rtc<'d> {
self.sleep(&config, wake_sources, delay);
}

/// enter sleep with the provided `config` and wake with the provided
/// `wake_sources`
/// Enter sleep with the provided `config` and wake with the provided
/// `wake_sources`.
#[cfg(any(esp32, esp32s3, esp32c3, esp32c6))]
pub fn sleep(
&mut self,
Expand All @@ -304,15 +333,15 @@ impl<'d> Rtc<'d> {
}

#[cfg(not(any(esp32c6, esp32h2)))]
/// RTC Watchdog Timer
/// RTC Watchdog Timer.
pub struct RtcClock;

#[cfg(not(any(esp32c6, esp32h2)))]
/// RTC Watchdog Timer driver
/// RTC Watchdog Timer driver.
impl RtcClock {
const CAL_FRACT: u32 = 19;

/// Enable or disable 8 MHz internal oscillator
/// Enable or disable 8 MHz internal oscillator.
///
/// Output from 8 MHz internal oscillator is passed into a configurable
/// divider, which by default divides the input clock frequency by 256.
Expand Down Expand Up @@ -352,7 +381,7 @@ impl RtcClock {
}
}

/// Get main XTAL frequency
/// Get main XTAL frequency.
/// This is the value stored in RTC register RTC_XTAL_FREQ_REG by the
/// bootloader, as passed to rtc_clk_init function.
pub fn get_xtal_freq() -> XtalClock {
Expand Down Expand Up @@ -380,7 +409,7 @@ impl RtcClock {
}
}

/// Get the RTC_SLOW_CLK source
/// Get the RTC_SLOW_CLK source.
#[cfg(not(any(esp32c6, esp32h2)))]
pub fn get_slow_freq() -> RtcSlowClock {
let rtc_cntl = unsafe { &*LPWR::PTR };
Expand All @@ -393,7 +422,7 @@ impl RtcClock {
}
}

/// Select source for RTC_SLOW_CLK
/// Select source for RTC_SLOW_CLK.
#[cfg(not(any(esp32c6, esp32h2)))]
fn set_slow_freq(slow_freq: RtcSlowClock) {
unsafe {
Expand All @@ -416,7 +445,7 @@ impl RtcClock {
crate::rom::ets_delay_us(300u32);
}

/// Select source for RTC_FAST_CLK
/// Select source for RTC_FAST_CLK.
#[cfg(not(any(esp32c6, esp32h2)))]
fn set_fast_freq(fast_freq: RtcFastClock) {
unsafe {
Expand Down Expand Up @@ -576,15 +605,15 @@ impl RtcClock {
cal_val
}

/// Measure ratio between XTAL frequency and RTC slow clock frequency
/// Measure ratio between XTAL frequency and RTC slow clock frequency.
fn get_calibration_ratio(cal_clk: RtcCalSel, slowclk_cycles: u32) -> u32 {
let xtal_cycles = RtcClock::calibrate_internal(cal_clk, slowclk_cycles) as u64;
let ratio = (xtal_cycles << RtcClock::CAL_FRACT) / slowclk_cycles as u64;

(ratio & (u32::MAX as u64)) as u32
}

/// Measure RTC slow clock's period, based on main XTAL frequency
/// Measure RTC slow clock's period, based on main XTAL frequency.
///
/// This function will time out and return 0 if the time for the given
/// number of cycles to be counted exceeds the expected time twice. This
Expand Down Expand Up @@ -619,6 +648,7 @@ impl RtcClock {
}

// TODO: implement for ESP32-C6, and H2
/// Return estimated XTAL frequency in MHz.
#[cfg(not(any(esp32c6, esp32h2)))]
pub(crate) fn estimate_xtal_frequency() -> u32 {
// Number of 8M/256 clock cycles to use for XTAL frequency estimation.
Expand All @@ -643,7 +673,7 @@ impl RtcClock {
}
}

/// Behavior of the RWDT stage if it times out
/// Behavior of the RWDT stage if it times out.
#[allow(unused)]
#[derive(Debug, Clone, Copy)]
enum RwdtStageAction {
Expand All @@ -654,7 +684,7 @@ enum RwdtStageAction {
ResetRtc = 4,
}

/// RTC Watchdog Timer
/// RTC Watchdog Timer.
pub struct Rwdt {
stg0_action: RwdtStageAction,
stg1_action: RwdtStageAction,
Expand All @@ -673,18 +703,19 @@ impl Default for Rwdt {
}
}

/// RTC Watchdog Timer driver
/// RTC Watchdog Timer driver.
impl Rwdt {
/// Enable the watchdog timer instance
/// Enable the watchdog timer instance.
pub fn enable(&mut self) {
self.set_enabled(true);
}

/// Disable the watchdog timer instance
/// Disable the watchdog timer instance.
pub fn disable(&mut self) {
self.set_enabled(false);
}

/// Listen for interrupts.
pub fn listen(&mut self) {
#[cfg(not(any(esp32c6, esp32h2)))]
let rtc_cntl = unsafe { &*LPWR::PTR };
Expand All @@ -705,6 +736,7 @@ impl Rwdt {
self.set_write_protection(true);
}

/// Stop listening for interrupts.
pub fn unlisten(&mut self) {
#[cfg(not(any(esp32c6, esp32h2)))]
let rtc_cntl = unsafe { &*LPWR::PTR };
Expand All @@ -725,6 +757,7 @@ impl Rwdt {
self.set_write_protection(true);
}

/// Clear interrupt.
pub fn clear_interrupt(&mut self) {
#[cfg(not(any(esp32c6, esp32h2)))]
let rtc_cntl = unsafe { &*LPWR::PTR };
Expand All @@ -738,6 +771,7 @@ impl Rwdt {
self.set_write_protection(true);
}

/// Check if the interrupt is set.
pub fn is_interrupt_set(&self) -> bool {
#[cfg(not(any(esp32c6, esp32h2)))]
let rtc_cntl = unsafe { &*LPWR::PTR };
Expand All @@ -747,6 +781,7 @@ impl Rwdt {
rtc_cntl.int_st().read().wdt().bit_is_set()
}

/// Feed the watchdog timer.
pub fn feed(&mut self) {
#[cfg(not(any(esp32c6, esp32h2)))]
let rtc_cntl = unsafe { &*LPWR::PTR };
Expand Down Expand Up @@ -784,6 +819,7 @@ impl Rwdt {
self.set_write_protection(true);
}

/// Configure timeout value in ms.
pub fn set_timeout(&mut self, timeout: MicrosDurationU64) {
#[cfg(not(any(esp32c6, esp32h2)))]
let rtc_cntl = unsafe { &*LPWR::PTR };
Expand Down Expand Up @@ -924,12 +960,14 @@ impl embedded_hal_02::watchdog::WatchdogDisable for Swd {
}
}

/// Return reset reason.
pub fn get_reset_reason(cpu: Cpu) -> Option<SocResetReason> {
let reason = crate::rom::rtc_get_reset_reason(cpu as u32);

SocResetReason::from_repr(reason as usize)
}

/// Return wakeup reason.
pub fn get_wakeup_cause() -> SleepSource {
if get_reset_reason(Cpu::ProCpu) != Some(SocResetReason::CoreDeepSleep) {
return SleepSource::Undefined;
Expand Down
2 changes: 1 addition & 1 deletion esp-hal/src/soc/esp32/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ pub extern "Rust" fn __init_data() -> bool {
#[export_name = "__post_init"]
unsafe fn post_init() {
// RTC domain must be enabled before we try to disable
let mut rtc = Rtc::new(LPWR::steal());
let mut rtc = Rtc::new(LPWR::steal(), None);
rtc.rwdt.disable();

Wdt::<TIMG0, crate::Blocking>::set_wdt_enabled(false);
Expand Down
2 changes: 1 addition & 1 deletion esp-hal/src/soc/esp32c2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub(crate) mod constants {
#[export_name = "__post_init"]
unsafe fn post_init() {
// RTC domain must be enabled before we try to disable
let mut rtc = Rtc::new(LPWR::steal());
let mut rtc = Rtc::new(LPWR::steal(), None);
rtc.swd.disable();
rtc.rwdt.disable();

Expand Down
2 changes: 1 addition & 1 deletion esp-hal/src/soc/esp32c3/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub(crate) mod constants {
#[export_name = "__post_init"]
unsafe fn post_init() {
// RTC domain must be enabled before we try to disable
let mut rtc = Rtc::new(LPWR::steal());
let mut rtc = Rtc::new(LPWR::steal(), None);
rtc.swd.disable();
rtc.rwdt.disable();

Expand Down
2 changes: 1 addition & 1 deletion esp-hal/src/soc/esp32c6/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ pub(crate) mod constants {
#[export_name = "__post_init"]
unsafe fn post_init() {
// RTC domain must be enabled before we try to disable
let mut rtc = Rtc::new(LPWR::steal());
let mut rtc = Rtc::new(LPWR::steal(), None);
rtc.swd.disable();
rtc.rwdt.disable();

Expand Down
2 changes: 1 addition & 1 deletion esp-hal/src/soc/esp32h2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub(crate) mod constants {
#[export_name = "__post_init"]
unsafe fn post_init() {
// RTC domain must be enabled before we try to disable
let mut rtc = Rtc::new(LPWR::steal());
let mut rtc = Rtc::new(LPWR::steal(), None);
rtc.swd.disable();
rtc.rwdt.disable();

Expand Down
2 changes: 1 addition & 1 deletion esp-hal/src/soc/esp32s2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ pub extern "Rust" fn __init_data() -> bool {
#[export_name = "__post_init"]
unsafe fn post_init() {
// RTC domain must be enabled before we try to disable
let mut rtc = Rtc::new(LPWR::steal());
let mut rtc = Rtc::new(LPWR::steal(), None);
rtc.rwdt.disable();

Wdt::<TIMG0, crate::Blocking>::set_wdt_enabled(false);
Expand Down
2 changes: 1 addition & 1 deletion esp-hal/src/soc/esp32s3/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ pub extern "Rust" fn __init_data() -> bool {
#[export_name = "__post_init"]
unsafe fn post_init() {
// RTC domain must be enabled before we try to disable
let mut rtc = Rtc::new(LPWR::steal());
let mut rtc = Rtc::new(LPWR::steal(), None);
rtc.rwdt.disable();

Wdt::<TIMG0, crate::Blocking>::set_wdt_enabled(false);
Expand Down
2 changes: 1 addition & 1 deletion esp-hal/src/timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
//! ## Example
//!
//! ```no_run
//! let mut rtc = Rtc::new(peripherals.LPWR);
//! let mut rtc = Rtc::new(peripherals.LPWR, None);
//!
//! // Create timer groups
//! let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
Expand Down
Loading
Loading