Skip to main content

esp_hal/rtc_cntl/sleep/
esp32.rs

1use super::SleepKind;
2use crate::{
3    peripherals::{BB, DPORT, I2S0, LPWR, NRX},
4    private::DropGuard,
5    rtc_cntl::{Rtc, WakeupSource},
6    soc::clocks::{self, ClockTree, CpuClkConfig},
7};
8
9// Approximate mapping of voltages to RTC_CNTL_DBIAS_WAK, RTC_CNTL_DBIAS_SLP,
10// RTC_CNTL_DIG_DBIAS_WAK, RTC_CNTL_DIG_DBIAS_SLP values.
11// Valid if RTC_CNTL_DBG_ATTEN is 0.
12/// RTC digital bias setting corresponding to 0.90V.
13pub const RTC_CNTL_DBIAS_0V90: u8 = 0;
14/// RTC digital bias setting corresponding to 0.95V.
15pub const RTC_CNTL_DBIAS_0V95: u8 = 1;
16/// RTC digital bias setting corresponding to 1.00V.
17pub const RTC_CNTL_DBIAS_1V00: u8 = 2;
18/// RTC digital bias setting corresponding to 1.05V.
19pub const RTC_CNTL_DBIAS_1V05: u8 = 3;
20/// RTC digital bias setting corresponding to 1.10V.
21pub const RTC_CNTL_DBIAS_1V10: u8 = 4;
22/// RTC digital bias setting corresponding to 1.15V.
23pub const RTC_CNTL_DBIAS_1V15: u8 = 5;
24/// RTC digital bias setting corresponding to 1.20V.
25pub const RTC_CNTL_DBIAS_1V20: u8 = 6;
26/// RTC digital bias setting corresponding to 1.25V.
27pub const RTC_CNTL_DBIAS_1V25: u8 = 7;
28
29// Various delays to be programmed into power control state machines
30/// Time (in microseconds) for waiting the XTL buffer to stabilize during sleep.
31pub const RTC_CNTL_XTL_BUF_WAIT_SLP_US: u32 = 1000;
32/// Cycles to wait for PLL buffer stabilization.
33pub const RTC_CNTL_PLL_BUF_WAIT_SLP_CYCLES: u8 = 1;
34/// Cycles to wait for the 8 MHz clock to stabilize.
35pub const RTC_CNTL_CK8M_WAIT_SLP_CYCLES: u8 = 4;
36/// Delay in cycles for wakeup signal to be applied.
37pub const RTC_CNTL_WAKEUP_DELAY_CYCLES: u8 = 7;
38/// Power-up cycles for other blocks.
39pub const RTC_CNTL_OTHER_BLOCKS_POWERUP_CYCLES: u8 = 1;
40/// Waits cycles for other blocks.
41pub const RTC_CNTL_OTHER_BLOCKS_WAIT_CYCLES: u16 = 1;
42/// Minimum sleep value (in cycles).
43pub const RTC_CNTL_MIN_SLP_VAL_MIN: u8 = 128;
44/// Default debug attenuation value.
45pub const RTC_CNTL_DBG_ATTEN_DEFAULT: u8 = 3;
46
47/// Power-up cycles for RTC memory.
48pub const RTC_MEM_POWERUP_CYCLES: u8 = RTC_CNTL_OTHER_BLOCKS_POWERUP_CYCLES;
49/// Waits cycles for RTC memory.
50pub const RTC_MEM_WAIT_CYCLES: u16 = RTC_CNTL_OTHER_BLOCKS_WAIT_CYCLES;
51/// Power-up cycles for ROM and RAM.
52pub const ROM_RAM_POWERUP_CYCLES: u8 = RTC_CNTL_OTHER_BLOCKS_POWERUP_CYCLES;
53/// Waits cycles for ROM and RAM.
54pub const ROM_RAM_WAIT_CYCLES: u16 = RTC_CNTL_OTHER_BLOCKS_WAIT_CYCLES;
55/// Power-up cycles for Wi-Fi.
56pub const WIFI_POWERUP_CYCLES: u8 = RTC_CNTL_OTHER_BLOCKS_POWERUP_CYCLES;
57/// Waits cycles for Wi-Fi.
58pub const WIFI_WAIT_CYCLES: u16 = RTC_CNTL_OTHER_BLOCKS_WAIT_CYCLES;
59/// Power-up cycles for RTC components.
60pub const RTC_POWERUP_CYCLES: u8 = RTC_CNTL_OTHER_BLOCKS_POWERUP_CYCLES;
61/// Waits cycles for RTC components.
62pub const RTC_WAIT_CYCLES: u16 = RTC_CNTL_OTHER_BLOCKS_WAIT_CYCLES;
63/// Power-up cycles for the digital wrap components.
64pub const DG_WRAP_POWERUP_CYCLES: u8 = RTC_CNTL_OTHER_BLOCKS_POWERUP_CYCLES;
65/// Waits cycles for the digital wrap components.
66pub const DG_WRAP_WAIT_CYCLES: u16 = RTC_CNTL_OTHER_BLOCKS_WAIT_CYCLES;
67
68/// Default wait cycles for the 8 MHz clock.
69pub const RTC_CNTL_CK8M_WAIT_DEFAULT: u8 = 20;
70/// Default wait cycles to enable the 8 MHz clock.
71pub const RTC_CK8M_ENABLE_WAIT_DEFAULT: u8 = 5;
72
73bitfield::bitfield! {
74    #[derive(Clone, Copy)]
75    /// Configuration for the RTC sleep behavior.
76    pub struct RtcSleepConfig(u32);
77    impl Debug;
78    /// force normal voltage in sleep mode (digital domain memory)
79    pub lslp_mem_inf_fpu, set_lslp_mem_inf_fpu: 0;
80    /// force normal voltage in sleep mode (RTC memory)
81    pub rtc_mem_inf_fpu, set_rtc_mem_inf_fpu: 1;
82    /// keep low voltage in sleep mode (even if ULP/touch is used)
83    pub rtc_mem_inf_follow_cpu, set_rtc_mem_inf_follow_cpu: 2;
84    /// power down RTC fast memory
85    pub rtc_fastmem_pd_en, set_rtc_fastmem_pd_en: 3;
86    /// power down RTC slow memory
87    pub rtc_slowmem_pd_en, set_rtc_slowmem_pd_en: 4;
88    /// power down RTC peripherals
89    pub rtc_peri_pd_en, set_rtc_peri_pd_en: 5;
90    /// power down WiFi
91    pub wifi_pd_en, set_wifi_pd_en: 6;
92    /// Powers down Internal 8M oscillator.
93    pub int_8m_pd_en, set_int_8m_pd_en: 7;
94    /// power down main RAM and ROM
95    pub rom_mem_pd_en, set_rom_mem_pd_en: 8;
96    /// power down digital domain
97    pub deep_slp, set_deep_slp: 9;
98    /// enable WDT flashboot mode
99    pub wdt_flashboot_mod_en, set_wdt_flashboot_mod_en: 10;
100    /// bias for digital domain, in active mode
101    pub u8, dig_dbias_wak, set_dig_dbias_wak: 13, 11;
102    /// bias for digital domain, in sleep mode
103    pub u8, dig_dbias_slp, set_dig_dbias_slp: 16, 14;
104    /// bias for RTC domain, in active mode
105    pub u8, rtc_dbias_wak, set_rtc_dbias_wak: 19, 17;
106    /// bias for RTC domain, in sleep mode
107    pub u8, rtc_dbias_slp, set_rtc_dbias_slp: 22, 20;
108    /// remove all peripheral force power up flags
109    pub lslp_meminf_pd, set_lslp_meminf_pd: 23;
110    /// power down VDDSDIO regulator
111    pub vddsdio_pd_en, set_vddsdio_pd_en: 24;
112    /// keep main XTAL powered up in sleep
113    pub xtal_fpu, set_xtal_fpu: 25;
114    /// enable deep sleep reject
115    pub deep_slp_reject, set_deep_slp_reject: 26;
116    /// enable light sleep reject
117    pub light_slp_reject, set_light_slp_reject: 27;
118}
119
120impl Default for RtcSleepConfig {
121    fn default() -> Self {
122        let mut cfg = Self(Default::default());
123        cfg.set_lslp_meminf_pd(true);
124        cfg.set_deep_slp_reject(true);
125        cfg.set_light_slp_reject(true);
126        cfg.set_dig_dbias_wak(RTC_CNTL_DBIAS_1V10);
127        cfg.set_dig_dbias_slp(RTC_CNTL_DBIAS_1V10);
128        cfg.set_rtc_dbias_wak(RTC_CNTL_DBIAS_1V10);
129        cfg.set_rtc_dbias_slp(RTC_CNTL_DBIAS_1V10);
130        cfg
131    }
132}
133
134impl RtcSleepConfig {
135    /// Configures the RTC for deep sleep mode.
136    pub fn deep() -> Self {
137        let mut cfg = Self::default();
138        cfg.set_deep_slp(true);
139        cfg.set_dig_dbias_slp(RTC_CNTL_DBIAS_0V90);
140        // cfg.set_rtc_dbias_slp(RTC_CNTL_DBIAS_0V90);
141        cfg.set_vddsdio_pd_en(true);
142        cfg.set_int_8m_pd_en(true);
143        cfg.set_xtal_fpu(false);
144        cfg.set_wifi_pd_en(true);
145        cfg.set_rom_mem_pd_en(true);
146        cfg.set_rtc_peri_pd_en(true);
147        cfg.set_rtc_fastmem_pd_en(true);
148        cfg.set_rtc_slowmem_pd_en(true);
149        cfg
150    }
151
152    pub(crate) fn is_deep_sleep(&self) -> bool {
153        self.deep_slp()
154    }
155
156    pub(crate) fn set_sleep_kind(&mut self, kind: SleepKind) {
157        self.set_deep_slp(kind == SleepKind::Deep);
158    }
159
160    pub(crate) fn base_settings(_rtc: &Rtc<'_>) {
161        // settings derived from esp-idf after basic boot
162        let rtc_cntl = LPWR::regs();
163
164        rtc_cntl.options0().modify(|_, w| {
165            w.bias_core_force_pu().clear_bit();
166            w.bias_core_folw_8m().set_bit();
167            w.bias_i2c_force_pu().clear_bit();
168            w.bias_i2c_folw_8m().set_bit();
169            w.bias_force_nosleep().clear_bit();
170            w.bias_sleep_folw_8m().set_bit();
171            w.xtl_force_pu().clear_bit()
172        });
173
174        rtc_cntl.reg().modify(|_, w| {
175            w.force_pu().clear_bit();
176            w.dboost_force_pu().clear_bit();
177            w.dboost_force_pd().set_bit()
178        });
179
180        rtc_cntl.pwc().modify(|_, w| {
181            w.slowmem_force_pu().clear_bit();
182            w.fastmem_force_pu().clear_bit();
183            w.force_noiso().clear_bit();
184            w.slowmem_force_noiso().clear_bit();
185            w.fastmem_force_noiso().clear_bit()
186        });
187
188        rtc_cntl.dig_pwc().modify(|_, w| {
189            w.dg_wrap_force_pu().clear_bit();
190            w.wifi_force_pu().clear_bit();
191            w.wifi_force_pd().set_bit();
192            w.inter_ram4_force_pu().clear_bit();
193            w.inter_ram3_force_pu().clear_bit();
194            w.inter_ram2_force_pu().clear_bit();
195            w.inter_ram1_force_pu().clear_bit();
196            w.inter_ram0_force_pu().clear_bit();
197            w.rom0_force_pu().clear_bit();
198            w.lslp_mem_force_pu().clear_bit()
199        });
200
201        rtc_cntl.dig_iso().modify(|_, w| {
202            w.dg_wrap_force_noiso().clear_bit();
203            w.wifi_force_noiso().clear_bit();
204            w.wifi_force_iso().set_bit();
205            w.inter_ram4_force_noiso().clear_bit();
206            w.inter_ram3_force_noiso().clear_bit();
207            w.inter_ram2_force_noiso().clear_bit();
208            w.inter_ram1_force_noiso().clear_bit();
209            w.inter_ram0_force_noiso().clear_bit();
210            w.rom0_force_noiso().clear_bit();
211            w.dg_pad_force_unhold().clear_bit();
212            w.dg_pad_force_noiso().clear_bit()
213        });
214
215        rtc_cntl.int_ena().modify(|_, w| w.brown_out().set_bit());
216    }
217
218    pub(crate) fn apply(&self) {
219        // like esp-idf rtc_sleep_init()
220        unsafe {
221            let rtc_cntl = LPWR::regs();
222
223            rtc_cntl.timer5().modify(|_, w| {
224                w.min_slp_val().bits(RTC_CNTL_MIN_SLP_VAL_MIN);
225                // set rtc memory timer
226                w.rtcmem_powerup_timer().bits(RTC_MEM_POWERUP_CYCLES);
227                w.rtcmem_wait_timer().bits(RTC_MEM_WAIT_CYCLES)
228            });
229
230            rtc_cntl.timer3().modify(|_, w| {
231                // set rom&ram timer
232                w.rom_ram_powerup_timer().bits(ROM_RAM_POWERUP_CYCLES);
233                w.rom_ram_wait_timer().bits(ROM_RAM_WAIT_CYCLES);
234                // set wifi timer
235                w.wifi_powerup_timer().bits(WIFI_POWERUP_CYCLES);
236                w.wifi_wait_timer().bits(WIFI_WAIT_CYCLES)
237            });
238
239            rtc_cntl.timer4().modify(|_, w| {
240                // set rtc peri timer
241                w.powerup_timer().bits(RTC_POWERUP_CYCLES);
242                w.wait_timer().bits(RTC_WAIT_CYCLES);
243                // set digital wrap timer
244                w.dg_wrap_powerup_timer().bits(DG_WRAP_POWERUP_CYCLES);
245                w.dg_wrap_wait_timer().bits(DG_WRAP_WAIT_CYCLES)
246            });
247
248            rtc_cntl
249                .dig_pwc()
250                .modify(|_, w| w.lslp_mem_force_pu().bit(self.lslp_mem_inf_fpu()));
251
252            // remove all peripheral force power up flags
253            if self.lslp_meminf_pd() {
254                rtc_cntl
255                    .dig_pwc()
256                    .modify(|_, w| w.lslp_mem_force_pu().clear_bit());
257
258                rtc_cntl.pwc().modify(|_, w| {
259                    w.slowmem_force_pu().clear_bit();
260                    w.fastmem_force_pu().clear_bit()
261                });
262
263                // esp-idf also clears these:
264
265                DPORT::regs()
266                    .mem_pd_mask()
267                    .modify(|_, w| w.lslp_mem_pd_mask().clear_bit());
268
269                I2S0::regs()
270                    .pd_conf()
271                    .modify(|_, w| w.plc_mem_force_pu().clear_bit().fifo_force_pu().clear_bit());
272
273                BB::regs()
274                    .bbpd_ctrl()
275                    .modify(|_, w| w.fft_force_pu().clear_bit().dc_est_force_pu().clear_bit());
276
277                NRX::regs().nrxpd_ctrl().modify(|_, w| {
278                    w.rx_rot_force_pu().clear_bit();
279                    w.vit_force_pu().clear_bit();
280                    w.demap_force_pu().clear_bit()
281                });
282                // (&*esp32::FE::ptr()).gen_ctrl.modify(|_, w| w
283                //     .iq_est_force_pu().clear_bit()
284                // );
285                //
286                // (&*esp32::FE2::ptr()).tx_interp_ctrl.modify(|_, w| w
287                //     .inf_force_pu().clear_bit()
288                // );
289            }
290
291            rtc_cntl.pwc().modify(|_, w| {
292                w.slowmem_folw_cpu().bit(self.rtc_mem_inf_follow_cpu());
293                w.fastmem_folw_cpu().bit(self.rtc_mem_inf_follow_cpu());
294
295                // TODO: does this need to be optional based on if there is something stored in
296                // fastmem?
297                //.fastmem_pd_en().bit(self.rtc_fastmem_pd_en())
298
299                w.fastmem_force_pu().bit(!self.rtc_fastmem_pd_en());
300                w.fastmem_force_lpu().bit(!self.rtc_fastmem_pd_en());
301                w.fastmem_force_noiso().bit(!self.rtc_fastmem_pd_en());
302                w.slowmem_pd_en().bit(self.rtc_slowmem_pd_en());
303                w.slowmem_force_pu().bit(!self.rtc_slowmem_pd_en());
304                w.slowmem_force_noiso().bit(!self.rtc_slowmem_pd_en());
305                w.slowmem_force_lpu().bit(!self.rtc_slowmem_pd_en());
306                w.pd_en().bit(self.rtc_peri_pd_en())
307            });
308
309            // rtc_cntl.dig_pwc.modify(|_, w| w
310            //     .wifi_pd_en().bit(self.wifi_pd_en())
311            //     .rom0_pd_en().bit(self.rom_mem_pd_en())
312            // );
313
314            if self.deep_slp() {
315                rtc_cntl.dig_iso().modify(|_, w| {
316                    w.dg_wrap_force_noiso().clear_bit();
317                    w.wifi_force_noiso().clear_bit();
318                    w.dg_pad_force_iso().clear_bit();
319                    w.dg_pad_force_noiso().clear_bit()
320                });
321
322                rtc_cntl.dig_pwc().modify(|_, w| {
323                    w.dg_wrap_pd_en().set_bit();
324                    w.dg_wrap_force_pu().clear_bit();
325                    w.dg_wrap_force_pd().clear_bit()
326                });
327
328                rtc_cntl.options0().modify(|_, w| {
329                    w.bias_force_nosleep().clear_bit();
330                    w.bb_i2c_force_pu().clear_bit()
331                });
332
333                rtc_cntl.ana_conf().modify(|_, w| {
334                    w.ckgen_i2c_pu().clear_bit();
335                    w.pll_i2c_pu().clear_bit();
336                    w.rfrx_pbus_pu().clear_bit();
337                    w.txrf_i2c_pu().clear_bit()
338                });
339            } else {
340                rtc_cntl
341                    .dig_pwc()
342                    .modify(|_, w| w.dg_wrap_pd_en().clear_bit());
343
344                rtc_cntl.bias_conf().modify(|_, w| w.dbg_atten().bits(0));
345            }
346
347            rtc_cntl
348                .options0()
349                .modify(|_, w| w.xtl_force_pu().bit(self.xtal_fpu()));
350
351            rtc_cntl
352                .clk_conf()
353                .modify(|_, w| w.ck8m_force_pu().bit(!self.int_8m_pd_en()));
354
355            // enable VDDSDIO control by state machine
356
357            rtc_cntl.sdio_conf().modify(|_, w| {
358                w.sdio_force().clear_bit();
359                w.sdio_pd_en().bit(self.vddsdio_pd_en())
360            });
361
362            rtc_cntl.reg().modify(|_, w| {
363                w.dbias_slp().bits(self.rtc_dbias_slp());
364                w.dbias_wak().bits(self.rtc_dbias_wak());
365                w.dig_dbias_slp().bits(self.dig_dbias_slp());
366                w.dig_dbias_wak().bits(self.dig_dbias_wak())
367            });
368
369            rtc_cntl.slp_reject_conf().modify(|_, w| {
370                w.deep_slp_reject_en().bit(self.deep_slp_reject());
371                w.light_slp_reject_en().bit(self.light_slp_reject())
372            });
373        }
374    }
375
376    /// Configures the wakeup and reject sources of the sleep.
377    ///
378    /// [`Self::enter_sleep`] requests the sleep after this call. The return value is a guard that
379    /// restores what sleep entry changed for the sleep only, so the caller keeps it until the
380    /// sleep ends.
381    #[crate::ram]
382    pub(crate) fn start_sleep(&self, wakeup_mask: u32, reject_mask: u32) -> impl Sized {
383        let restore_clock_config = ClockTree::with(|clocks| {
384            let old_root = clocks.cpu_clk();
385
386            clocks::configure_cpu_clk(clocks, CpuClkConfig::Xtal);
387
388            // Restore the old clock settings when we return
389            DropGuard::new((), move |_| {
390                ClockTree::with(|clocks| {
391                    crate::soc::clocks::reconfigure_pll(clocks);
392                    if let Some(old_root) = old_root {
393                        clocks::configure_cpu_clk(clocks, old_root);
394                    }
395                });
396            })
397        });
398
399        LPWR::regs()
400            .reset_state()
401            .modify(|_, w| w.procpu_stat_vector_sel().set_bit());
402
403        // set bits for what can wake us up
404        LPWR::regs()
405            .wakeup_state()
406            .modify(|_, w| unsafe { w.wakeup_ena().bits(wakeup_mask as u16) });
407
408        // esp32 has no reject-source mask. GPIO and SDIO have one reject enable each, and no other
409        // source can reject a sleep. The reject bits that `apply` wrote arm these enables.
410        let rejects = enumset::EnumSet::<WakeupSource>::from_u32_truncated(reject_mask);
411        LPWR::regs().slp_reject_conf().modify(|_, w| {
412            w.gpio_reject_en().bit(rejects.contains(WakeupSource::Gpio));
413            w.sdio_reject_en().bit(rejects.contains(WakeupSource::Sdio))
414        });
415
416        restore_clock_config
417    }
418
419    /// Requests the sleep.
420    ///
421    /// The caller waits for the result of the request.
422    #[inline(always)]
423    pub(crate) fn enter_sleep(&self) -> bool {
424        LPWR::regs().state0().modify(|_, w| w.sleep_en().set_bit());
425        super::wait_for_sleep_result()
426    }
427
428    pub(crate) fn finish_sleep(&self) {
429        // In deep sleep mode, we never get here
430        LPWR::regs().int_clr().write(|w| {
431            w.slp_reject().clear_bit_by_one();
432            w.slp_wakeup().clear_bit_by_one()
433        });
434
435        // restore DBG_ATTEN to the default value
436
437        LPWR::regs()
438            .bias_conf()
439            .modify(|_, w| unsafe { w.dbg_atten().bits(RTC_CNTL_DBG_ATTEN_DEFAULT) });
440    }
441}