feat(bod): Add support for bod on esp32h21

This commit is contained in:
C.S.M
2026-03-20 16:03:11 +08:00
parent 118f64c32a
commit f491e94863
8 changed files with 215 additions and 33 deletions
@@ -117,15 +117,13 @@ __attribute__((weak)) void bootloader_clock_configure(void)
#elif CONFIG_IDF_TARGET_ESP32H21
// CLR ENA
CLEAR_PERI_REG_MASK(LP_WDT_INT_ENA_REG, LP_WDT_SUPER_WDT_INT_ENA); /* SWD */
// TODO [ESP32H21] IDF-11530
// CLEAR_PERI_REG_MASK(LP_ANA_LP_INT_ENA_REG, LP_ANA_BOD_MODE0_LP_INT_ENA); /* BROWN_OUT */
CLEAR_PERI_REG_MASK(LP_ANA_LP_INT_ENA_REG, LP_ANA_BOD_MODE0_LP_INT_ENA); /* BROWN_OUT */
CLEAR_PERI_REG_MASK(LP_WDT_INT_ENA_REG, LP_WDT_LP_WDT_INT_ENA); /* WDT */
CLEAR_PERI_REG_MASK(PMU_HP_INT_ENA_REG, PMU_SOC_WAKEUP_INT_ENA); /* SLP_REJECT */
CLEAR_PERI_REG_MASK(PMU_HP_INT_ENA_REG, PMU_SOC_SLEEP_REJECT_INT_ENA); /* SLP_WAKEUP */
// SET CLR
SET_PERI_REG_MASK(LP_WDT_INT_CLR_REG, LP_WDT_SUPER_WDT_INT_CLR); /* SWD */
// TODO [ESP32H21] IDF-11530
// SET_PERI_REG_MASK(LP_ANA_LP_INT_CLR_REG, LP_ANA_BOD_MODE0_LP_INT_CLR); /* BROWN_OUT */
SET_PERI_REG_MASK(LP_ANA_LP_INT_CLR_REG, LP_ANA_BOD_MODE0_LP_INT_CLR); /* BROWN_OUT */
SET_PERI_REG_MASK(LP_WDT_INT_CLR_REG, LP_WDT_LP_WDT_INT_CLR); /* WDT */
SET_PERI_REG_MASK(PMU_HP_INT_CLR_REG, PMU_SOC_WAKEUP_INT_CLR); /* SLP_REJECT */
SET_PERI_REG_MASK(PMU_HP_INT_CLR_REG, PMU_SOC_SLEEP_REJECT_INT_CLR);
@@ -37,6 +37,7 @@
#include "hal/mmu_hal.h"
#include "hal/cache_hal.h"
#include "hal/lpwdt_ll.h"
#include "hal/brownout_ll.h"
#include "soc/lp_wdt_reg.h"
#include "soc/pmu_reg.h"
#include "hal/efuse_hal.h"
@@ -96,8 +97,7 @@ static inline void bootloader_ana_reset_config(void)
//Enable super WDT reset.
bootloader_ana_super_wdt_reset_config(true);
//Enable BOD reset (mode1)
//TODO: [ESP32H21] IDF-11530
// brownout_ll_ana_reset_enable(true);
brownout_ll_ana_reset_enable(true);
}
esp_err_t bootloader_init(void)
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -13,18 +13,6 @@ void bootloader_ana_super_wdt_reset_config(bool enable)
REG_CLR_BIT(LP_ANA_FIB_ENABLE_REG, LP_ANALOG_PERI_LP_ANA_FIB_SUPER_WDT_RST);
}
//TODO: [ESP32H21] IDF-11531, there is a `bootloader_ana_bod_reset_config` in verify code, please check
void bootloader_ana_bod_reset_config(bool enable)
{
REG_CLR_BIT(LP_ANA_FIB_ENABLE_REG, LP_ANALOG_PERI_LP_ANA_FIB_BOD_RST);
if (enable) {
REG_SET_BIT(LP_ANA_BOD_MODE1_CNTL_REG, LP_ANA_BOD_MODE1_RESET_ENA);
} else {
REG_CLR_BIT(LP_ANA_BOD_MODE1_CNTL_REG, LP_ANA_BOD_MODE1_RESET_ENA);
}
}
//Not supported but common bootloader calls the function. Do nothing
void bootloader_ana_clock_glitch_reset_config(bool enable)
{
@@ -0,0 +1,148 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*******************************************************************************
* NOTICE
* The ll is not public api, don't use in application code.
* See readme.md in hal/readme.md
******************************************************************************/
#pragma once
#include <stdbool.h>
#include "esp_bit_defs.h"
#include "soc/lp_analog_peri_struct.h"
#include "hal/regi2c_ctrl.h"
#include "hal/psdet_types.h"
#include "soc/regi2c_brownout.h"
#define BROWNOUT_DETECTOR_LL_INTERRUPT_MASK (BIT(31))
#define BROWNOUT_DETECTOR_LL_FIB_ENABLE (BIT(1))
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief suspend the flash when a brown out happens.
*
* @param enable true: suspend flash. false: not suspend
*/
static inline void brownout_ll_enable_flash_suspend(bool enable)
{
LP_ANA_PERI.ana_bod_mode0_cntl.ana_bod_mode0_close_flash_ena = enable;
}
/**
* @brief power down the RF circuits when a brown out happens
*
* @param enable true: power down. false: not power down.
*/
static inline void brownout_ll_enable_rf_power_down(bool enable)
{
LP_ANA_PERI.ana_bod_mode0_cntl.ana_bod_mode0_pd_rf_ena = enable;
}
/**
* @brief Configure the brown out detector to do a hardware reset
*
* @note: If brown out interrupt is also used, the hardware reset can be disabled,
* because we can call software reset in the interrupt handler.
*
* @param reset_ena true: enable reset. false: disable reset.
* @param reset_wait brown out reset wait cycles
* @param reset_level reset level
*/
static inline void brownout_ll_reset_config(bool reset_ena, uint32_t reset_wait, brownout_reset_level_t reset_level)
{
LP_ANA_PERI.ana_bod_mode0_cntl.ana_bod_mode0_reset_wait = reset_wait;
LP_ANA_PERI.ana_bod_mode0_cntl.ana_bod_mode0_reset_ena = reset_ena;
LP_ANA_PERI.ana_bod_mode0_cntl.ana_bod_mode0_reset_sel = reset_level;
}
/**
* @brief Set brown out threshold voltage
*
* @param threshold brownout threshold
*/
static inline void brownout_ll_set_threshold(uint8_t threshold)
{
REGI2C_WRITE_MASK(I2C_BOD, I2C_BOD_THRESHOLD, threshold);
}
/**
* @brief Set this bit to enable the brown out detection
*
* @param bod_enable true: enable, false: disable
*/
static inline void brownout_ll_bod_enable(bool bod_enable)
{
LP_ANA_PERI.ana_bod_mode0_cntl.ana_bod_mode0_intr_ena = bod_enable;
}
/**
* @brief configure the waiting cycles before sending an interrupt
*
* @param cycle waiting cycles.
*/
static inline void brownout_ll_set_intr_wait_cycles(uint8_t cycle)
{
LP_ANA_PERI.ana_bod_mode0_cntl.ana_bod_mode0_intr_wait = cycle;
}
/**
* @brief Enable brown out interrupt
*
* @param enable true: enable, false: disable
*/
static inline void brownout_ll_intr_enable(bool enable)
{
LP_ANA_PERI.ana_int_ena.ana_bod_mode0_int_ena = enable;
}
/**
* @brief Enable brownout hardware reset (mode1)
*
* @param enable true: enable, false: disable
*/
static inline void brownout_ll_ana_reset_enable(bool enable)
{
// give BOD mode1 control permission to the software
LP_ANA_PERI.ana_fib_enable.val &= ~BROWNOUT_DETECTOR_LL_FIB_ENABLE;
// then we can enable or disable if we want the BOD mode1 to reset the system
LP_ANA_PERI.ana_bod_mode1_cntl.ana_bod_mode1_reset_ena = enable;
}
/**
* @brief Clear interrupt bits.
*/
__attribute__((always_inline))
static inline void brownout_ll_intr_clear(void)
{
LP_ANA_PERI.ana_int_clr.val = BROWNOUT_DETECTOR_LL_INTERRUPT_MASK;
}
/**
* @brief Clear BOD internal count.
*/
static inline void brownout_ll_clear_count(void)
{
LP_ANA_PERI.ana_bod_mode0_cntl.ana_bod_mode0_cnt_clr = 1;
LP_ANA_PERI.ana_bod_mode0_cntl.ana_bod_mode0_cnt_clr = 0;
}
/**
* @brief Get interrupt status register address
*
* @return Register address
*/
static inline volatile void *brownout_ll_intr_get_status_reg(void)
{
return &LP_ANA_PERI.ana_int_st;
}
#ifdef __cplusplus
}
#endif
@@ -13,7 +13,7 @@ menu "Power Supplier"
choice ESP_BROWNOUT_DET_LVL_SEL
prompt "Brownout voltage level"
depends on ESP_BROWNOUT_DET
default ESP_BROWNOUT_DET_LVL_SEL_0
default ESP_BROWNOUT_DET_LVL_SEL_4
help
The brownout detector will reset the chip when the supply voltage is approximately
below this level. Note that there may be some variation of brownout voltage level
@@ -21,34 +21,54 @@ menu "Power Supplier"
#The voltage levels here are estimates, more work needs to be done to figure out the exact voltages
#of the brownout threshold levels.
config ESP_BROWNOUT_DET_LVL_SEL_15
bool "3.77V"
config ESP_BROWNOUT_DET_LVL_SEL_14
bool "3.68V"
config ESP_BROWNOUT_DET_LVL_SEL_13
bool "3.58V"
config ESP_BROWNOUT_DET_LVL_SEL_12
bool "3.47V"
config ESP_BROWNOUT_DET_LVL_SEL_11
bool "3.37V"
config ESP_BROWNOUT_DET_LVL_SEL_10
bool "3.26V"
config ESP_BROWNOUT_DET_LVL_SEL_9
bool "3.16V"
config ESP_BROWNOUT_DET_LVL_SEL_8
bool "3.06V"
config ESP_BROWNOUT_DET_LVL_SEL_7
bool "2.94V"
bool "2.96V"
config ESP_BROWNOUT_DET_LVL_SEL_6
bool "2.88V"
bool "2.86V"
config ESP_BROWNOUT_DET_LVL_SEL_5
bool "2.83V"
bool "2.75V"
config ESP_BROWNOUT_DET_LVL_SEL_4
bool "2.78V"
bool "2.66V"
config ESP_BROWNOUT_DET_LVL_SEL_3
bool "2.73V"
bool "2.55V"
config ESP_BROWNOUT_DET_LVL_SEL_2
bool "2.67V"
config ESP_BROWNOUT_DET_LVL_SEL_1
bool "2.62V"
config ESP_BROWNOUT_DET_LVL_SEL_0
bool "2.57V"
bool "2.45V"
endchoice
config ESP_BROWNOUT_DET_LVL
int
default 0 if ESP_BROWNOUT_DET_LVL_SEL_0
default 1 if ESP_BROWNOUT_DET_LVL_SEL_1
default 2 if ESP_BROWNOUT_DET_LVL_SEL_2
default 3 if ESP_BROWNOUT_DET_LVL_SEL_3
default 4 if ESP_BROWNOUT_DET_LVL_SEL_4
default 5 if ESP_BROWNOUT_DET_LVL_SEL_5
default 6 if ESP_BROWNOUT_DET_LVL_SEL_6
default 7 if ESP_BROWNOUT_DET_LVL_SEL_7
default 8 if ESP_BROWNOUT_DET_LVL_SEL_8
default 9 if ESP_BROWNOUT_DET_LVL_SEL_9
default 10 if ESP_BROWNOUT_DET_LVL_SEL_10
default 11 if ESP_BROWNOUT_DET_LVL_SEL_11
default 12 if ESP_BROWNOUT_DET_LVL_SEL_12
default 13 if ESP_BROWNOUT_DET_LVL_SEL_13
default 14 if ESP_BROWNOUT_DET_LVL_SEL_14
default 15 if ESP_BROWNOUT_DET_LVL_SEL_15
config ESP_BROWNOUT_USE_INTR
bool
@@ -111,6 +111,10 @@ config SOC_SECURE_BOOT_SUPPORTED
bool
default y
config SOC_BOD_SUPPORTED
bool
default y
config SOC_PMU_SUPPORTED
bool
default y
@@ -0,0 +1,24 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
#pragma once
#include "regi2c_pmu.h"
/**
* @file regi2c_brownout.h
* @brief Register definitions for brownout detector
*
* This file lists register fields of the brownout detector, located on an internal configuration
* bus. These definitions are used via macros defined in regi2c_ctrl.h.
*/
#define I2C_BOD I2C_PMU
#define I2C_BOD_HOSTID I2C_PMU_HOSTID
#define I2C_BOD_THRESHOLD 0xD
#define I2C_BOD_THRESHOLD_MSB 6
#define I2C_BOD_THRESHOLD_LSB 3
@@ -58,7 +58,7 @@
#define SOC_ECDSA_SUPPORTED 1
#define SOC_FLASH_ENC_SUPPORTED 1
#define SOC_SECURE_BOOT_SUPPORTED 1
// #define SOC_BOD_SUPPORTED 1 //TODO: [ESP32H21] IDF-11530
#define SOC_BOD_SUPPORTED 1
// #define SOC_APM_SUPPORTED 1 //TODO: [ESP32H21] IDF-11494
#define SOC_PMU_SUPPORTED 1
#define SOC_RTC_TIMER_SUPPORTED 1