Skip to main content

esp_hal/rtc_cntl/sleep/
esp32.rs

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