#![cfg_attr(docsrs, procmacros::doc_replace)]
use crate::{
peripherals::LPWR,
rtc_cntl::{
WakeupSource,
sleep::{SleepResource, WrappedSleepConfig},
},
};
#[derive(Debug, Clone, Copy)]
pub enum UlpCoreWakeupSource {
HpCpu,
Timer(UlpCoreTimerCycles),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct UlpCoreTimerCycles {
cycles: u32,
}
impl UlpCoreTimerCycles {
pub const fn new(cycles: u32) -> Self {
::core::assert!(
cycles <= 0xFFFFFF,
"ULP Timer cycles must be between 0 and 0xFFFFFF (inclusive)."
);
Self { cycles }
}
fn cycles(self) -> u32 {
self.cycles
}
}
impl Default for UlpCoreTimerCycles {
fn default() -> Self {
Self { cycles: 200 }
}
}
pub struct UlpCore<'d> {
_lp_core: crate::peripherals::ULP_RISCV_CORE<'d>,
}
impl<'d> UlpCore<'d> {
pub fn new(lp_core: crate::peripherals::ULP_RISCV_CORE<'d>) -> Self {
let lp_ram =
unsafe { core::slice::from_raw_parts_mut(0x5000_0000 as *mut u32, 8 * 1024 / 4) };
lp_ram.fill(0u32);
Self { _lp_core: lp_core }
}
pub fn run(&mut self, wakeup_src: UlpCoreWakeupSource) {
ulp_run(wakeup_src);
}
pub fn enable_wakeup(&mut self, config: WakeupConfig) {
enable_wakeup(config);
}
pub fn disable_wakeup(&mut self) {
WakeupSource::UlpRiscv.disable();
WakeupSource::UlpRiscvTrap.disable();
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, procmacros::BuilderLite)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub struct WakeupConfig {
software_interrupt: bool,
trap: bool,
}
impl Default for WakeupConfig {
fn default() -> Self {
Self {
software_interrupt: true,
trap: true,
}
}
}
fn enable_wakeup(config: WakeupConfig) {
for (source, enable) in [
(WakeupSource::UlpRiscv, config.software_interrupt),
(WakeupSource::UlpRiscvTrap, config.trap),
] {
if enable {
source.enable_with_hooks(Some(keep_low_power_domain), None);
} else {
source.disable();
}
}
}
#[crate::ram]
fn keep_low_power_domain(config: &mut WrappedSleepConfig<'_>) {
config.keep_alive(SleepResource::LpMemory);
config.keep_alive(SleepResource::LpPeripherals);
}
#[allow(unused)] fn ulp_stop() {
LPWR::regs()
.ulp_cp_timer()
.modify(|_, w| w.ulp_cp_slp_timer_en().clear_bit());
LPWR::regs()
.cocpu_ctrl()
.modify(|_, w| w.cocpu_done().set_bit());
LPWR::regs()
.cocpu_ctrl()
.modify(|_, w| w.cocpu_shut_reset_en().set_bit());
}
fn ulp_run(wakeup_src: UlpCoreWakeupSource) {
let rtc_cntl = LPWR::regs();
rtc_cntl
.cocpu_ctrl()
.modify(|_, w| w.cocpu_shut_reset_en().set_bit());
rtc_cntl
.ulp_cp_timer()
.modify(|_, w| w.ulp_cp_slp_timer_en().clear_bit());
crate::rom::ets_delay_us(20);
rtc_cntl
.cocpu_ctrl()
.modify(|_, w| w.cocpu_done_force().set_bit());
ulp_config_wakeup_source(wakeup_src);
rtc_cntl
.cocpu_ctrl()
.modify(|_, w| w.cocpu_sel().clear_bit());
crate::rom::ets_delay_us(20);
rtc_cntl.int_clr().write(|w| {
w.cocpu()
.clear_bit_by_one()
.cocpu_trap()
.clear_bit_by_one()
.ulp_cp()
.clear_bit_by_one()
});
}
fn ulp_config_wakeup_source(wakeup_src: UlpCoreWakeupSource) {
fn configure_timer(cycles: u32) {
LPWR::regs()
.ulp_cp_timer_1()
.write(|w| unsafe { w.ulp_cp_timer_slp_cycle().bits(cycles << 8) });
LPWR::regs()
.ulp_cp_ctrl()
.modify(|_, w| w.ulp_cp_force_start_top().clear_bit());
LPWR::regs()
.ulp_cp_timer()
.modify(|_, w| w.ulp_cp_slp_timer_en().set_bit());
}
match wakeup_src {
UlpCoreWakeupSource::HpCpu => {
configure_timer(0);
}
UlpCoreWakeupSource::Timer(sleep_cycles) => {
configure_timer(sleep_cycles.cycles());
}
}
}