feat(brownout): Add brownout detector support on esp32c61

This commit is contained in:
C.S.M 2024-08-20 13:36:08 +08:00
parent e76c2c4b53
commit 8078ad7840
8 changed files with 237 additions and 4 deletions

View File

@ -43,6 +43,7 @@
#include "hal/efuse_hal.h"
#include "hal/lpwdt_ll.h"
#include "hal/regi2c_ctrl_ll.h"
#include "hal/brownout_ll.h"
static const char *TAG = "boot.esp32c61";
@ -94,8 +95,8 @@ static inline void bootloader_ana_reset_config(void)
{
//Enable super WDT reset.
bootloader_ana_super_wdt_reset_config(true);
//Enable BOD reset TODO: IDF-9254 BOD support
// brownout_ll_ana_reset_enable(true);
//Enable BOD reset (mode1)
brownout_ll_ana_reset_enable(true);
}
esp_err_t bootloader_init(void)

View File

@ -22,6 +22,8 @@
#include "hal/brownout_hal.h"
#include "hal/brownout_ll.h"
#include "sdkconfig.h"
#include "esp_rom_uart.h"
#include "hal/uart_ll.h"
#if defined(CONFIG_ESP_BROWNOUT_DET_LVL)
#define BROWNOUT_DET_LVL CONFIG_ESP_BROWNOUT_DET_LVL
@ -57,6 +59,13 @@ IRAM_ATTR static void rtc_brownout_isr_handler(void *arg)
ESP_DRAM_LOGI(TAG, "Brownout detector was triggered\r\n\r\n");
}
// Flush any data left in UART FIFOs
for (int i = 0; i < SOC_UART_HP_NUM; ++i) {
if (uart_ll_is_enabled(i)) {
esp_rom_output_tx_wait_idle(i);
}
}
esp_rom_software_reset_system();
while (true) {
;
@ -77,7 +86,7 @@ void esp_brownout_init(void)
brownout_hal_config(&cfg);
brownout_ll_intr_clear();
#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C61 // TODO: ESP32C61] IDF-9254
#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C61
// TODO IDF-6606: LP_RTC_TIMER interrupt source is shared by lp_timer and brownout detector, but lp_timer interrupt
// is not used now. An interrupt allocator is needed when lp_timer intr gets supported.
esp_intr_alloc_intrstatus(ETS_LP_RTC_TIMER_INTR_SOURCE, ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_SHARED, (uint32_t)brownout_ll_intr_get_status_reg(), BROWNOUT_DETECTOR_LL_INTERRUPT_MASK, &rtc_brownout_isr_handler, NULL, NULL);

View File

@ -0,0 +1,45 @@
menu "Brownout Detector"
config ESP_BROWNOUT_DET
bool "Hardware brownout detect & reset"
depends on !IDF_ENV_FPGA
default y
help
The ESP32-C61 has a built-in brownout detector which can detect if the voltage is lower than
a specific value. If this happens, it will reset the chip in order to prevent unintended
behaviour.
choice ESP_BROWNOUT_DET_LVL_SEL
prompt "Brownout voltage level"
depends on ESP_BROWNOUT_DET
default ESP_BROWNOUT_DET_LVL_SEL_7
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
between each chip.
#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_7
bool "2.51V"
config ESP_BROWNOUT_DET_LVL_SEL_6
bool "2.64V"
config ESP_BROWNOUT_DET_LVL_SEL_5
bool "2.76V"
config ESP_BROWNOUT_DET_LVL_SEL_4
bool "2.92V"
config ESP_BROWNOUT_DET_LVL_SEL_3
bool "3.10V"
config ESP_BROWNOUT_DET_LVL_SEL_2
bool "3.27V"
endchoice
config ESP_BROWNOUT_DET_LVL
int
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
endmenu

View File

@ -113,6 +113,8 @@ static inline void brownout_ll_ana_reset_enable(bool enable)
LP_ANA_PERI.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.bod_mode1_cntl.bod_mode1_reset_ena = enable;
// Disable the power glitch detect.
LP_ANA_PERI.fib_enable.val &= ~(BIT2|BIT3|BIT4|BIT5);
}
/**

View File

@ -0,0 +1,150 @@
/*
* SPDX-FileCopyrightText: 2024 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.bod_mode0_cntl.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.bod_mode0_cntl.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.bod_mode0_cntl.bod_mode0_reset_wait = reset_wait;
LP_ANA.bod_mode0_cntl.bod_mode0_reset_ena = reset_ena;
LP_ANA.bod_mode0_cntl.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.bod_mode0_cntl.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.bod_mode0_cntl.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.int_ena.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.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.bod_mode1_cntl.bod_mode1_reset_ena = enable;
// Disable the power glitch detect.
LP_ANA.fib_enable.val &= ~(BIT2|BIT3|BIT4|BIT5);
}
/**
* @brief Clear interrupt bits.
*/
__attribute__((always_inline))
static inline void brownout_ll_intr_clear(void)
{
LP_ANA.int_clr.bod_mode0_int_clr = 1;
}
/**
* @brief Clear BOD internal count.
*/
static inline void brownout_ll_clear_count(void)
{
LP_ANA.bod_mode0_cntl.bod_mode0_cnt_clr = 1;
LP_ANA.bod_mode0_cntl.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.int_st;
}
#ifdef __cplusplus
}
#endif

View File

@ -79,6 +79,10 @@ config SOC_SECURE_BOOT_SUPPORTED
bool
default y
config SOC_BOD_SUPPORTED
bool
default y
config SOC_PMU_SUPPORTED
bool
default y

View File

@ -0,0 +1,22 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
/**
* @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 0x61
#define I2C_BOD_HOSTID 0
#define I2C_BOD_THRESHOLD 0x5
#define I2C_BOD_THRESHOLD_MSB 2
#define I2C_BOD_THRESHOLD_LSB 0

View File

@ -46,7 +46,7 @@
#define SOC_ECC_EXTENDED_MODES_SUPPORTED 1
#define SOC_FLASH_ENC_SUPPORTED 1
#define SOC_SECURE_BOOT_SUPPORTED 1
// \#define SOC_BOD_SUPPORTED 1 //TODO: [ESP32C61] IDF-9254
#define SOC_BOD_SUPPORTED 1
// \#define SOC_APM_SUPPORTED 1 //TODO: [ESP32C61] IDF-9230
#define SOC_PMU_SUPPORTED 1 //TODO: [ESP32C61] IDF-9250
// \#define SOC_LP_TIMER_SUPPORTED 1 //TODO: [ESP32C61] IDF-9244