Using RTC with Backup Battery on ESP32-P4
Using RTC with Backup Battery on ESP32-P4
I’m new to ESP and currently working with the ESP32-P4 on a custom board. I want to use the RTC with a backup battery so that it keeps running when the main power is removed.
I have connected VBAT to a CR1220 backup battery, following the ESP32-P4 datasheet.
I have a few questions:
1.How can I enable and use the RTC with battery backup on the ESP32-P4?
2.Which configurations need to be changed in menuconfig to support this?
3.Are there example codes available for reading/writing the RTC time and verifying that it retains the correct time after a power loss?
4.Do I need to configure any special registers or settings for RTC backup mode?
Any guidance, example code, or reference documentation would be very helpful.
Thank you!
-
ahsrabrifat
- Posts: 201
- Joined: Sat Jan 18, 2025 2:31 pm
Re: Using RTC with Backup Battery on ESP32-P4
Re: Using RTC with Backup Battery on ESP32-P4
I am not familiar with the configuration. Could you please share any documentation on that? I am using ESP-IDF v5.5.
-
ahsrabrifat
- Posts: 201
- Joined: Sat Jan 18, 2025 2:31 pm
Re: Using RTC with Backup Battery on ESP32-P4
@Sudheesh Did you make it work?
First link "ESP32-P4 Battery Backup Solution" is for "ESP-IoT-Solution" and not for "ESP-Idf" ... If I look into file which I need modify there is no "pmu_sleep_start" function...
Any solution for ESP-IDF? I need to keep RTC if power is loss... NTP is not option because there is no internet or loacal connection(No LAN or WiFi)...
Re: Using RTC with Backup Battery on ESP32-P4
Has anyone had luck with this? Using VSCode extension I can find VBAT settings that seem relevant. I am specifically trying to keep the RTC through power loss. Following the above links gave me a variety of results. I was able to get RTC to persist through power loss, but booting became very inconsistent. It would be nice if Espressif could provide an example or improved documentation.
Re: Using RTC with Backup Battery on ESP32-P4
ESP32-P4 RTC Time Persistence Across Power Cycles — Approaches Tried
Hardware
- Board: Waveshare ESP32-P4-WIFI6-Touch-LCD-7B
- SoC: ESP32-P4 rev 1.3
- ESP-IDF: v5.4
- VBAT: CR1220 coin cell, measured 3.27V, seated in onboard battery holder
- VBAT circuit: CR1220 connected to ESP_VBAT pin via onboard holder (confirmed in schematic — VBAT feeds the LP domain power input)
- Peripherals using SDIO: SD card on SDMMC Slot 0 (4-bit, 40MHz), WiFi via ESP32-C6 coprocessor on SDIO Slot 1 (esp_hosted, 4-bit, 40MHz)
Code: Select all
gettimeofday()The goal was to maintain wall-clock time across power outages using the CR1220 battery, without relying on NTP or deep sleep.
Relevant sdkconfig
Code: Select all
CONFIG_RTC_CLK_SRC_INT_RC=y
CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y
CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER=y
CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT=y
CONFIG_SOC_RTC_FAST_MEM_SUPPORTED=y
CONFIG_SOC_RTC_MEM_SUPPORTED=yCode: Select all
gettimeofday()Code: Select all
boot_time + time_since_boot- is stored in LP_STORE2/3 registers (
Code: Select all
boot_time/Code: Select all
LP_SYSTEM_REG_LP_STORE2_REG) viaCode: Select all
LP_SYSTEM_REG_LP_STORE3_REGinCode: Select all
esp_time_impl_set_boot_time()Code: Select all
components/newlib/port/esp_time_impl.c - uses
Code: Select all
time_since_bootwhereCode: Select all
s_microseconds_offset + esp_system_get_time()bridges the ESP timer to the RTC counterCode: Select all
s_microseconds_offset - writes:
Code: Select all
settimeofday()into LP_STORE2/3Code: Select all
boot_time = now - time_since_boot - The 48-bit RTC counter () provides the monotonic reference
Code: Select all
esp_rtc_get_time_us()
[hr]
Approach 1: Baseline — System Calls Only (the P4 "onboard RTC" shim)
Implementation: Replaced the external DS3231 I2C driver with a shim that wraps
Code: Select all
gettimeofday()Code: Select all
settimeofday()Result:
Code: Select all
gettimeofday()Code: Select all
[DIAG] Reset: POWERON, RTC counter: 3298603 us (0.0 hrs), epoch: 3
Code: Select all
ESP_RST_POWERONRoot cause: Every reset — including serial-triggered resets — appears as
Code: Select all
RESET_REASON_CHIP_POWER_ON[hr]
Approach 2: NVS Bootstrap
Implementation: On every boot, before the RTC driver reads
Code: Select all
gettimeofday()Code: Select all
last_sync_tsCode: Select all
gettimeofday()Code: Select all
settimeofday()Also saved
Code: Select all
rtc_ref_usCode: Select all
esp_rtc_get_time_us()Code: Select all
current_time = nvs_epoch + (rtc_counter_now - rtc_counter_saved) / 1e6Result: Clock was primed to approximately correct time (minute resolution from NVS). Components started immediately without the 27-second NTP wait. However, the RTC counter delta was always zero because the counter resets on every boot — so the "second-accurate VBAT refinement" path never activated. The time was stale by the duration of the power outage.
[hr]
Approach 3: PMU VBAT Auto-Switch via Direct Register Write
Implementation: Based on Espressif's ESP32-P4 VBAT documentation, set the PMU to auto-switch the LP domain to VBAT when main power drops:
Code: Select all
// In DS3231::init(), before any SDIO initialization:
REG_SET_FIELD(PMU_HP_SLEEP_LP_DIG_POWER_REG, PMU_HP_SLEEP_VDDBAT_MODE, 2); // AUTO mode
REG_SET_BIT(PMU_VDDBAT_CFG_REG, PMU_VDDBAT_SW_UPDATE);
// Poll for activation:
while (2 != REG_GET_FIELD(PMU_VDDBAT_CFG_REG, PMU_ANA_VDDBAT_MODE)) { ... }
The VBAT switching did work for time persistence. After power cycling (unplug, wait, replug), the boot log showed:
Code: Select all
MAIN: RTC Time: 2026-04-03 12:16:33
However, both SDIO peripherals crashed on the VBAT-wake boot:
- SD card (SDMMC Slot 0): →
Code: Select all
sdmmc_init_sd_ssr: sdmmc_send_cmd returned 0x107Code: Select all
ESP_ERR_TIMEOUT - WiFi SDIO (Slot 1, esp_hosted):
Code: Select all
assert failed: xQueueSemaphoreTake queue.c:1709 (( pxQueue ))
Code: Select all
RESET_REASON_CHIP_POWER_ONCode: Select all
components/esp_system/port/soc/esp32p4/clk.cCode: Select all
CHIP_POWER_ONCode: Select all
if (rst_reason == RESET_REASON_CHIP_POWER_ON) {
// These only run on cold boot:
REG_CLR_BIT(LP_CLKRST_HP_CLK_CTRL_REG, LP_CLKRST_HP_SDIO_PLL2_CLK_EN);
REG_CLR_BIT(LP_CLKRST_HP_CLK_CTRL_REG, LP_CLKRST_HP_SDIO_PLL1_CLK_EN);
REG_CLR_BIT(LP_CLKRST_HP_CLK_CTRL_REG, LP_CLKRST_HP_SDIO_PLL0_CLK_EN);
// ... more LP clock cleanup ...
}
Additional finding:
Code: Select all
PMU_ANA_VDDBAT_MODECode: Select all
PMU_VDDBAT_CFG_REG[hr]
Approach 4: LP Peripheral Force-Reset + SDIO Clock Cleanup + VBAT Enable
Implementation: Before enabling VBAT, force-reset LP peripherals and replay the
Code: Select all
CHIP_POWER_ONCode: Select all
// Step 1: Force-reset LP peripherals
PMU.power.lp_peri.force_reset = 1;
esp_rom_delay_us(100);
PMU.power.lp_peri.force_reset = 0;
// Step 2: Clear stale SDIO/LP clocks (from clk.c:375-399)
REG_CLR_BIT(LP_CLKRST_HP_CLK_CTRL_REG, LP_CLKRST_HP_SDIO_PLL2_CLK_EN);
REG_CLR_BIT(LP_CLKRST_HP_CLK_CTRL_REG, LP_CLKRST_HP_SDIO_PLL1_CLK_EN);
REG_CLR_BIT(LP_CLKRST_HP_CLK_CTRL_REG, LP_CLKRST_HP_SDIO_PLL0_CLK_EN);
// ... all other LP clock gates from clk.c ...
// Step 3: Enable VBAT
REG_SET_FIELD(PMU_HP_SLEEP_LP_DIG_POWER_REG, PMU_HP_SLEEP_VDDBAT_MODE, 2);
REG_SET_BIT(PMU_VDDBAT_CFG_REG, PMU_VDDBAT_SW_UPDATE);
The
Code: Select all
lp_periCode: Select all
LP_STORE4Code: Select all
W (4868) rtc_clk: invalid RTC_XTAL_FREQ_REG value, assume 40MHz (×6 times)
Code: Select all
rst:0x0 (N/A),boot:0xf (SPI_FAST_FLASH_BOOT)
invalid reset
Guru Meditation Error: Core 0 panic'ed (Illegal instruction)
PC: 0x4fc02ba6 ← LP ROM address space (0x4fc0xxxx)
Code: Select all
lp_peri[hr]
Approach 5: RTC_NOINIT_ATTR (investigated, not attempted)
Finding: We investigated using
Code: Select all
RTC_NOINIT_ATTRCode: Select all
{magic, epoch, rtc_counter}- persistence tests are explicitly disabled for ESP32-P4 in ESP-IDF 5.4 due to issue IDF-9564:
Code: Select all
RTC_NOINIT_ATTRCode: Select all
// components/esp_system/test_apps/.../test_reset_reason.c:27-29 #if (CONFIG_SOC_RTC_FAST_MEM_SUPPORTED || CONFIG_SOC_RTC_SLOW_MEM_SUPPORTED) && !CONFIG_IDF_TARGET_ESP32P4 #define CHECK_RTC_MEM 1 #endif - The LP RAM linker section exists (at
Code: Select all
lp_ram_seg, 8KB) and the macro is defined (not empty), but behavior is unvalidated on P4.Code: Select all
0x50108000 - Even if it worked, without the RTC counter surviving, we'd only have the epoch snapshot, not elapsed time.
Summary of Findings
Code: Select all
Approach | RTC Counter? | LP_STORE? | SDIO? | Usable?
--------------------------|-------------|-----------|-----------|---------------------------
Baseline (no VBAT) | No (zero) | No (zero) | Yes | No time persistence
NVS bootstrap | N/A (zero) | N/A | Yes | Minute-res only, stale
VBAT auto-switch | YES | YES | NO crash | Time works, SDIO broken
LP force-reset + VBAT | Destroyed | Destroyed | Crashes | Unusable
RTC_NOINIT_ATTR | N/A (IDF-9564) | Untested/disabled on P4
Questions for Espressif
1. Is there a supported way to enable VBAT power switching for the LP domain without going through the deep sleep infrastructure? Our device runs in full-power mode and experiences unexpected power loss. We need the PMU to be pre-configured so that when VDDA drops, it automatically switches to VBAT — without having called
Code: Select all
esp_deep_sleep_start()2. Can the SDIO PLL clock cleanup in
Code: Select all
clk.c:375-399Code: Select all
RESET_REASON_CHIP_POWER_ON3. Is there a way to selectively reset LP peripherals (SDIO clocks, GPIO pads) without resetting the LP_STORE registers and RTC counter?
Code: Select all
PMU.power.lp_peri.force_reset4. What is the status of IDF-9564 (
Code: Select all
RTC_NOINIT_ATTR5. The
Code: Select all
esp_vbat[hr]
Resolution
We ultimately attached an external DS3231 I2C RTC module (SDA=GPIO7, SCL=GPIO8) with its own battery backup. This provides sub-second time accuracy across power cycles without any dependency on the ESP32-P4's LP domain persistence.
Who is online
Users browsing this forum: trendictionbot and 7 guests