use super::{Ext0WakeupSource, Ext1WakeupSource, TimerWakeupSource, WakeSource, WakeTriggers};
use crate::{
gpio::{RtcFunction, RtcPin},
peripherals::{BB, DPORT, I2S0, LPWR, NRX, RTC_IO},
rtc_cntl::{Rtc, sleep::WakeupLevel},
};
pub const RTC_CNTL_DBIAS_0V90: u8 = 0;
pub const RTC_CNTL_DBIAS_0V95: u8 = 1;
pub const RTC_CNTL_DBIAS_1V00: u8 = 2;
pub const RTC_CNTL_DBIAS_1V05: u8 = 3;
pub const RTC_CNTL_DBIAS_1V10: u8 = 4;
pub const RTC_CNTL_DBIAS_1V15: u8 = 5;
pub const RTC_CNTL_DBIAS_1V20: u8 = 6;
pub const RTC_CNTL_DBIAS_1V25: u8 = 7;
pub const RTC_CNTL_XTL_BUF_WAIT_SLP_US: u32 = 1000;
pub const RTC_CNTL_PLL_BUF_WAIT_SLP_CYCLES: u8 = 1;
pub const RTC_CNTL_CK8M_WAIT_SLP_CYCLES: u8 = 4;
pub const RTC_CNTL_WAKEUP_DELAY_CYCLES: u8 = 7;
pub const RTC_CNTL_OTHER_BLOCKS_POWERUP_CYCLES: u8 = 1;
pub const RTC_CNTL_OTHER_BLOCKS_WAIT_CYCLES: u16 = 1;
pub const RTC_CNTL_MIN_SLP_VAL_MIN: u8 = 128;
pub const RTC_CNTL_DBG_ATTEN_DEFAULT: u8 = 3;
pub const RTC_MEM_POWERUP_CYCLES: u8 = RTC_CNTL_OTHER_BLOCKS_POWERUP_CYCLES;
pub const RTC_MEM_WAIT_CYCLES: u16 = RTC_CNTL_OTHER_BLOCKS_WAIT_CYCLES;
pub const ROM_RAM_POWERUP_CYCLES: u8 = RTC_CNTL_OTHER_BLOCKS_POWERUP_CYCLES;
pub const ROM_RAM_WAIT_CYCLES: u16 = RTC_CNTL_OTHER_BLOCKS_WAIT_CYCLES;
pub const WIFI_POWERUP_CYCLES: u8 = RTC_CNTL_OTHER_BLOCKS_POWERUP_CYCLES;
pub const WIFI_WAIT_CYCLES: u16 = RTC_CNTL_OTHER_BLOCKS_WAIT_CYCLES;
pub const RTC_POWERUP_CYCLES: u8 = RTC_CNTL_OTHER_BLOCKS_POWERUP_CYCLES;
pub const RTC_WAIT_CYCLES: u16 = RTC_CNTL_OTHER_BLOCKS_WAIT_CYCLES;
pub const DG_WRAP_POWERUP_CYCLES: u8 = RTC_CNTL_OTHER_BLOCKS_POWERUP_CYCLES;
pub const DG_WRAP_WAIT_CYCLES: u16 = RTC_CNTL_OTHER_BLOCKS_WAIT_CYCLES;
pub const RTC_CNTL_CK8M_WAIT_DEFAULT: u8 = 20;
pub const RTC_CK8M_ENABLE_WAIT_DEFAULT: u8 = 5;
impl WakeSource for TimerWakeupSource {
fn apply(
&self,
rtc: &Rtc<'_>,
triggers: &mut WakeTriggers,
_sleep_config: &mut RtcSleepConfig,
) {
triggers.set_timer(true);
let ticks = crate::clock::us_to_rtc_ticks(self.duration.as_micros() as u64);
let now = rtc.time_since_boot_raw();
let time_in_ticks = now + ticks;
unsafe {
LPWR::regs()
.slp_timer0()
.write(|w| w.slp_val_lo().bits((time_in_ticks & 0xffffffff) as u32));
LPWR::regs().slp_timer1().write(|w| {
w.slp_val_hi()
.bits(((time_in_ticks >> 32) & 0xffff) as u16)
.main_timer_alarm_en()
.set_bit()
});
}
}
}
impl<P: RtcPin> WakeSource for Ext0WakeupSource<P> {
fn apply(
&self,
_rtc: &Rtc<'_>,
triggers: &mut WakeTriggers,
sleep_config: &mut RtcSleepConfig,
) {
sleep_config.set_rtc_peri_pd_en(false);
triggers.set_ext0(true);
self.pin
.borrow_mut()
.rtc_set_config(true, true, RtcFunction::Rtc);
unsafe {
RTC_IO::regs()
.ext_wakeup0()
.modify(|_, w| w.sel().bits(self.pin.borrow().rtc_number()));
LPWR::regs()
.ext_wakeup_conf()
.modify(|_r, w| w.ext_wakeup0_lv().bit(self.level == WakeupLevel::High));
}
}
}
impl<P: RtcPin> Drop for Ext0WakeupSource<P> {
fn drop(&mut self) {
self.pin
.borrow_mut()
.rtc_set_config(true, false, RtcFunction::Rtc);
}
}
impl WakeSource for Ext1WakeupSource<'_, '_> {
fn apply(
&self,
_rtc: &Rtc<'_>,
triggers: &mut WakeTriggers,
sleep_config: &mut RtcSleepConfig,
) {
sleep_config.set_rtc_peri_pd_en(false);
triggers.set_ext1(true);
let mut pins = self.pins.borrow_mut();
let mut bits = 0u32;
for pin in pins.iter_mut() {
pin.rtc_set_config(true, true, RtcFunction::Rtc);
bits |= 1 << pin.rtc_number();
}
LPWR::regs()
.ext_wakeup1()
.modify(|_, w| w.status_clr().set_bit());
LPWR::regs()
.ext_wakeup1()
.modify(|_, w| unsafe { w.sel().bits(bits) });
LPWR::regs()
.ext_wakeup_conf()
.modify(|_r, w| w.ext_wakeup1_lv().bit(self.level == WakeupLevel::High));
}
}
impl Drop for Ext1WakeupSource<'_, '_> {
fn drop(&mut self) {
let mut pins = self.pins.borrow_mut();
for pin in pins.iter_mut() {
pin.rtc_set_config(true, false, RtcFunction::Rtc);
}
}
}
bitfield::bitfield! {
#[derive(Clone, Copy)]
pub struct RtcSleepConfig(u32);
impl Debug;
pub lslp_mem_inf_fpu, set_lslp_mem_inf_fpu: 0;
pub rtc_mem_inf_fpu, set_rtc_mem_inf_fpu: 1;
pub rtc_mem_inf_follow_cpu, set_rtc_mem_inf_follow_cpu: 2;
pub rtc_fastmem_pd_en, set_rtc_fastmem_pd_en: 3;
pub rtc_slowmem_pd_en, set_rtc_slowmem_pd_en: 4;
pub rtc_peri_pd_en, set_rtc_peri_pd_en: 5;
pub wifi_pd_en, set_wifi_pd_en: 6;
pub int_8m_pd_en, set_int_8m_pd_en: 7;
pub rom_mem_pd_en, set_rom_mem_pd_en: 8;
pub deep_slp, set_deep_slp: 9;
pub wdt_flashboot_mod_en, set_wdt_flashboot_mod_en: 10;
pub u8, dig_dbias_wak, set_dig_dbias_wak: 13, 11;
pub u8, dig_dbias_slp, set_dig_dbias_slp: 16, 14;
pub u8, rtc_dbias_wak, set_rtc_dbias_wak: 19, 17;
pub u8, rtc_dbias_slp, set_rtc_dbias_slp: 22, 20;
pub lslp_meminf_pd, set_lslp_meminf_pd: 23;
pub vddsdio_pd_en, set_vddsdio_pd_en: 24;
pub xtal_fpu, set_xtal_fpu: 25;
pub deep_slp_reject, set_deep_slp_reject: 26;
pub light_slp_reject, set_light_slp_reject: 27;
}
impl Default for RtcSleepConfig {
fn default() -> Self {
let mut cfg = Self(Default::default());
cfg.set_lslp_meminf_pd(true);
cfg.set_deep_slp_reject(true);
cfg.set_light_slp_reject(true);
cfg.set_dig_dbias_wak(RTC_CNTL_DBIAS_1V10);
cfg.set_dig_dbias_slp(RTC_CNTL_DBIAS_1V10);
cfg.set_rtc_dbias_wak(RTC_CNTL_DBIAS_1V10);
cfg.set_rtc_dbias_slp(RTC_CNTL_DBIAS_1V10);
cfg
}
}
impl RtcSleepConfig {
pub fn deep() -> Self {
let mut cfg = Self::default();
cfg.set_deep_slp(true);
cfg.set_dig_dbias_slp(RTC_CNTL_DBIAS_0V90);
cfg.set_vddsdio_pd_en(true);
cfg.set_int_8m_pd_en(true);
cfg.set_xtal_fpu(false);
cfg.set_wifi_pd_en(true);
cfg.set_rom_mem_pd_en(true);
cfg.set_rtc_peri_pd_en(true);
cfg.set_rtc_fastmem_pd_en(true);
cfg.set_rtc_slowmem_pd_en(true);
cfg
}
pub(crate) fn base_settings(_rtc: &Rtc<'_>) {
let rtc_cntl = LPWR::regs();
rtc_cntl.options0().modify(|_, w| {
w.bias_core_force_pu()
.clear_bit()
.bias_core_folw_8m()
.set_bit()
.bias_i2c_force_pu()
.clear_bit()
.bias_i2c_folw_8m()
.set_bit()
.bias_force_nosleep()
.clear_bit()
.bias_sleep_folw_8m()
.set_bit()
.xtl_force_pu()
.clear_bit()
});
rtc_cntl.reg().modify(|_, w| {
w.force_pu()
.clear_bit()
.dboost_force_pu()
.clear_bit()
.dboost_force_pd()
.set_bit()
});
rtc_cntl.pwc().modify(|_, w| {
w.slowmem_force_pu()
.clear_bit()
.fastmem_force_pu()
.clear_bit()
.force_noiso()
.clear_bit()
.slowmem_force_noiso()
.clear_bit()
.fastmem_force_noiso()
.clear_bit()
});
rtc_cntl.dig_pwc().modify(|_, w| {
w.dg_wrap_force_pu()
.clear_bit()
.wifi_force_pu()
.clear_bit()
.wifi_force_pd()
.set_bit()
.inter_ram4_force_pu()
.clear_bit()
.inter_ram3_force_pu()
.clear_bit()
.inter_ram2_force_pu()
.clear_bit()
.inter_ram1_force_pu()
.clear_bit()
.inter_ram0_force_pu()
.clear_bit()
.rom0_force_pu()
.clear_bit()
.lslp_mem_force_pu()
.clear_bit()
});
rtc_cntl.dig_iso().modify(|_, w| {
w.dg_wrap_force_noiso()
.clear_bit()
.wifi_force_noiso()
.clear_bit()
.wifi_force_iso()
.set_bit()
.inter_ram4_force_noiso()
.clear_bit()
.inter_ram3_force_noiso()
.clear_bit()
.inter_ram2_force_noiso()
.clear_bit()
.inter_ram1_force_noiso()
.clear_bit()
.inter_ram0_force_noiso()
.clear_bit()
.rom0_force_noiso()
.clear_bit()
.dg_pad_force_unhold()
.clear_bit()
.dg_pad_force_noiso()
.clear_bit()
});
rtc_cntl.int_ena().modify(|_, w| w.brown_out().set_bit());
}
pub(crate) fn apply(&self) {
unsafe {
let rtc_cntl = LPWR::regs();
rtc_cntl.timer5().modify(|_, w| {
w.min_slp_val()
.bits(RTC_CNTL_MIN_SLP_VAL_MIN)
.rtcmem_powerup_timer()
.bits(RTC_MEM_POWERUP_CYCLES)
.rtcmem_wait_timer()
.bits(RTC_MEM_WAIT_CYCLES)
});
rtc_cntl.timer3().modify(|_, w| {
w
.rom_ram_powerup_timer()
.bits(ROM_RAM_POWERUP_CYCLES)
.rom_ram_wait_timer()
.bits(ROM_RAM_WAIT_CYCLES)
.wifi_powerup_timer()
.bits(WIFI_POWERUP_CYCLES)
.wifi_wait_timer()
.bits(WIFI_WAIT_CYCLES)
});
rtc_cntl.timer4().modify(|_, w| {
w
.powerup_timer()
.bits(RTC_POWERUP_CYCLES)
.wait_timer()
.bits(RTC_WAIT_CYCLES)
.dg_wrap_powerup_timer()
.bits(DG_WRAP_POWERUP_CYCLES)
.dg_wrap_wait_timer()
.bits(DG_WRAP_WAIT_CYCLES)
});
rtc_cntl
.dig_pwc()
.modify(|_, w| w.lslp_mem_force_pu().bit(self.lslp_mem_inf_fpu()));
if self.lslp_meminf_pd() {
rtc_cntl
.dig_pwc()
.modify(|_, w| w.lslp_mem_force_pu().clear_bit());
rtc_cntl.pwc().modify(|_, w| {
w.slowmem_force_pu()
.clear_bit()
.fastmem_force_pu()
.clear_bit()
});
DPORT::regs()
.mem_pd_mask()
.modify(|_, w| w.lslp_mem_pd_mask().clear_bit());
I2S0::regs()
.pd_conf()
.modify(|_, w| w.plc_mem_force_pu().clear_bit().fifo_force_pu().clear_bit());
BB::regs()
.bbpd_ctrl()
.modify(|_, w| w.fft_force_pu().clear_bit().dc_est_force_pu().clear_bit());
NRX::regs().nrxpd_ctrl().modify(|_, w| {
w.rx_rot_force_pu()
.clear_bit()
.vit_force_pu()
.clear_bit()
.demap_force_pu()
.clear_bit()
});
}
rtc_cntl.pwc().modify(|_, w| {
w.slowmem_folw_cpu()
.bit(self.rtc_mem_inf_follow_cpu())
.fastmem_folw_cpu()
.bit(self.rtc_mem_inf_follow_cpu())
.fastmem_force_pu()
.bit(!self.rtc_fastmem_pd_en())
.fastmem_force_lpu()
.bit(!self.rtc_fastmem_pd_en())
.fastmem_force_noiso()
.bit(!self.rtc_fastmem_pd_en())
.slowmem_pd_en()
.bit(self.rtc_slowmem_pd_en())
.slowmem_force_pu()
.bit(!self.rtc_slowmem_pd_en())
.slowmem_force_noiso()
.bit(!self.rtc_slowmem_pd_en())
.slowmem_force_lpu()
.bit(!self.rtc_slowmem_pd_en())
.pd_en()
.bit(self.rtc_peri_pd_en())
});
if self.deep_slp() {
rtc_cntl.dig_iso().modify(|_, w| {
w.dg_wrap_force_noiso()
.clear_bit()
.wifi_force_noiso()
.clear_bit()
.dg_pad_force_iso()
.clear_bit()
.dg_pad_force_noiso()
.clear_bit()
});
rtc_cntl.dig_pwc().modify(|_, w| {
w.dg_wrap_pd_en()
.set_bit()
.dg_wrap_force_pu()
.clear_bit()
.dg_wrap_force_pd()
.clear_bit()
});
rtc_cntl.options0().modify(|_, w| {
w.bias_force_nosleep()
.clear_bit()
.bb_i2c_force_pu()
.clear_bit()
});
rtc_cntl.ana_conf().modify(|_, w| {
w.ckgen_i2c_pu()
.clear_bit()
.pll_i2c_pu()
.clear_bit()
.rfrx_pbus_pu()
.clear_bit()
.txrf_i2c_pu()
.clear_bit()
});
} else {
rtc_cntl
.dig_pwc()
.modify(|_, w| w.dg_wrap_pd_en().clear_bit());
rtc_cntl.bias_conf().modify(|_, w| w.dbg_atten().bits(0));
}
rtc_cntl
.options0()
.modify(|_, w| w.xtl_force_pu().bit(self.xtal_fpu()));
rtc_cntl
.clk_conf()
.modify(|_, w| w.ck8m_force_pu().bit(!self.int_8m_pd_en()));
rtc_cntl.sdio_conf().modify(|_, w| {
w.sdio_force()
.clear_bit()
.sdio_pd_en()
.bit(self.vddsdio_pd_en())
});
rtc_cntl.reg().modify(|_, w| {
w.dbias_slp()
.bits(self.rtc_dbias_slp())
.dbias_wak()
.bits(self.rtc_dbias_wak())
.dig_dbias_slp()
.bits(self.dig_dbias_slp())
.dig_dbias_wak()
.bits(self.dig_dbias_wak())
});
rtc_cntl.slp_reject_conf().modify(|_, w| {
w.deep_slp_reject_en()
.bit(self.deep_slp_reject())
.light_slp_reject_en()
.bit(self.light_slp_reject())
});
}
}
pub(crate) fn start_sleep(&self, wakeup_triggers: WakeTriggers) {
LPWR::regs()
.reset_state()
.modify(|_, w| w.procpu_stat_vector_sel().set_bit());
LPWR::regs()
.wakeup_state()
.modify(|_, w| unsafe { w.wakeup_ena().bits(wakeup_triggers.0) });
LPWR::regs()
.state0()
.write(|w| w.sleep_en().set_bit().slp_wakeup().set_bit());
}
pub(crate) fn finish_sleep(&self) {
LPWR::regs().int_clr().write(|w| {
w.slp_reject()
.clear_bit_by_one()
.slp_wakeup()
.clear_bit_by_one()
});
LPWR::regs()
.bias_conf()
.modify(|_, w| unsafe { w.dbg_atten().bits(RTC_CNTL_DBG_ATTEN_DEFAULT) });
}
}