Brownout Detection Interrupt

maldus
Posts: 83
Joined: Wed Jun 06, 2018 1:41 pm

Brownout Detection Interrupt

Postby maldus » Tue Aug 21, 2018 3:11 pm

Hello everyone,
If I understand correctly the esp32 chip has an internal Brownout Detector module that can be configured to reset the board when below a specific voltage level with

Code: Select all

make menuconfig
in an esp-idf environment.
Is it possible to receive an interrupt signal (and consequently run a custom handler) on BOD firing? I would like to save some data on power off. I cannot find any resource on this so I fear it's not possible, but it also seems a pretty basic functionality to have.

ESP_igrr
Posts: 2071
Joined: Tue Dec 01, 2015 8:37 am

Re: Brownout Detection Interrupt

Postby ESP_igrr » Tue Aug 21, 2018 4:14 pm

Hi maldus,

Attaching a handler to BOD interrupt is fairly easy, please check this source file: https://github.com/espressif/esp-idf/bl ... brownout.c. Basically you can disable IDF built-in BOD function using menuconfig, and enable BOD from your own code, attaching custom interrupt handler.

maldus
Posts: 83
Joined: Wed Jun 06, 2018 1:41 pm

Re: Brownout Detection Interrupt

Postby maldus » Thu Aug 23, 2018 12:41 pm

Hi,
many thanks for your hint; I was successfully able to run an interrupt on BOD. The reason I wanted to achieve this is to save some data on poweroff (few bytes, nothing big). I tried using the internal flash with nvs, but it doesn't work.
Maybe the flash nvs is not reliable enough in a poweroff situation? Could someone take a look at my code and tell me if there is anything obviously flawed?

Code: Select all

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "nvs.h"
#include "soc/soc.h"
#include "soc/cpu.h"
#include "soc/rtc_cntl_reg.h"
#include "driver/rtc_cntl.h"

#ifdef CONFIG_BROWNOUT_DET_LVL
#define BROWNOUT_DET_LVL CONFIG_BROWNOUT_DET_LVL
#else
#define BROWNOUT_DET_LVL 5
#endif //CONFIG_BROWNOUT_DET_LVL

#define CONFIG_BROWNOUT_DET_LVL_SEL_5 1


void low_voltage_save() {
    int32_t saved_counter = 0;
    nvs_handle my_handle;
    esp_err_t err = nvs_open("storage", NVS_READWRITE, &my_handle);
    if (err != ESP_OK) {
        ets_printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));
    } else {
        while(saved_counter < 100) {
            saved_counter++;
            err = nvs_set_i32(my_handle, "saved_counter", saved_counter);
            err = nvs_commit(my_handle);

        }
        // Close
        nvs_close(my_handle);
        REG_WRITE(RTC_CNTL_INT_CLR_REG, RTC_CNTL_BROWN_OUT_INT_CLR);
        esp_cpu_stall(!xPortGetCoreID());
        ets_printf("\r\nBrownout detector was triggered\r\n\r\n");
        //esp_restart_noos();
        while(1) {
            vTaskDelay(1 / portTICK_PERIOD_MS);
        }
    }


}



void brownout_init()
{
    REG_WRITE(RTC_CNTL_BROWN_OUT_REG,
            RTC_CNTL_BROWN_OUT_ENA /* Enable BOD */
            | RTC_CNTL_BROWN_OUT_PD_RF_ENA /* Automatically power down RF */
            /* Reset timeout must be set to >1 even if BOR feature is not used */
            | (2 << RTC_CNTL_BROWN_OUT_RST_WAIT_S)
            | (BROWNOUT_DET_LVL << RTC_CNTL_DBROWN_OUT_THRES_S));

    ESP_ERROR_CHECK( rtc_isr_register(low_voltage_save, NULL, RTC_CNTL_BROWN_OUT_INT_ENA_M) );
    printf("Initialized BOD\n");

    REG_SET_BIT(RTC_CNTL_INT_ENA_REG, RTC_CNTL_BROWN_OUT_INT_ENA_M);
}


void app_main()
{
    // Initialize NVS
    brownout_init();
    int32_t saved_counter = 0; // value will default to 0, if not set yet in NVS
    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        // NVS partition was truncated and needs to be erased
        // Retry nvs_flash_init
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
    }
    ESP_ERROR_CHECK( err );

    // Open
    printf("\n");
    printf("Opening Non-Volatile Storage (NVS) handle... ");
    nvs_handle my_handle;
    err = nvs_open("storage", NVS_READWRITE, &my_handle);
    if (err != ESP_OK) {
        printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));
    } else {
        printf("Done\n");

        // Read
        printf("Reading restart counter from NVS ... ");
        err = nvs_get_i32(my_handle, "saved_counter", &saved_counter);
        switch (err) {
            case ESP_OK:
                printf("Done\n");
                printf("Restart counter = %d\n", saved_counter);
                break;
            case ESP_ERR_NVS_NOT_FOUND:
                printf("The value is not initialized yet!\n");
                break;
            default :
                printf("Error (%s) reading!\n", esp_err_to_name(err));
        }

       // Close
        nvs_close(my_handle);
    }

    printf("\n");

    while (1) {
        printf("Restart counter = %d\n", saved_counter);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}


And this is the output. I trigger the BOD by shutting down the power source, and the saved value appears uninitialized on the next reset. If I lower the voltage to 2.7V (without shutting it down completely) the BOD interrupt is triggered and the data is saved correctly.

Code: Select all

$ make monitor
MONITOR
--- idf_monitor on /dev/ttyUSB0 115200 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:4940
load:0x40078000,len:8920
load:0x40080400,len:5832
entry 0x400806f4
I (91) cpu_start: Pro cpu up.
I (91) cpu_start: Single core mode
I (92) heap_init: Initializing. RAM available for dynamic allocation:
I (95) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (101) heap_init: At 3FFB2808 len 0002D7F8 (181 KiB): DRAM
I (107) heap_init: At 3FFE0440 len 00003BC0 (14 KiB): D/IRAM
I (113) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (120) heap_init: At 40088268 len 00017D98 (95 KiB): IRAM
I (126) cpu_start: Pro cpu start user code
I (144) cpu_start: Starting scheduler on PRO CPU.
Initialized BOD

Opening Non-Volatile Storage (NVS) handle... Done
Reading restart counter from NVS ... The value is not initialized yet!

Restart counter = 0
Restart counter = 0
Restart counter = 0
Restart counter = 0
Restart counter = 0

Brownout detector was triggered

ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
flash read err, 1000
ets_main.c 371
ets Jun  8 2016 00:22:57

rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:4940
load:0x40078000,len:8920
load:0x40080400,len:5832
entry 0x400806f4
I (92) cpu_start: Pro cpu up.
I (92) cpu_start: Single core mode
I (92) heap_init: Initializing. RAM available for dynamic allocation:
I (95) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (101) heap_init: At 3FFB2808 len 0002D7F8 (181 KiB): DRAM
I (108) heap_init: At 3FFE0440 len 00003BC0 (14 KiB): D/IRAM
I (114) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (120) heap_init: At 40088268 len 00017D98 (95 KiB): IRAM
I (127) cpu_start: Pro cpu start user code
I (144) cpu_start: Starting scheduler on PRO CPU.
Initialized BOD

Opening Non-Volatile Storage (NVS) handle... Done
Reading restart counter from NVS ... The value is not initialized yet!

Restart counter = 0
Restart counter = 0

ESP_igrr
Posts: 2071
Joined: Tue Dec 01, 2015 8:37 am

Re: Brownout Detection Interrupt

Postby ESP_igrr » Thu Aug 23, 2018 1:09 pm


maldus
Posts: 83
Joined: Wed Jun 06, 2018 1:41 pm

Re: Brownout Detection Interrupt

Postby maldus » Fri Aug 24, 2018 12:20 pm

Thanks again for the hint, I suspected the NVS was not to be trusted in such an extreme scenario.

User avatar
urbanze
Posts: 301
Joined: Sat Jun 10, 2017 9:55 pm
Location: Brazil

Re: Brownout Detection Interrupt

Postby urbanze » Fri Aug 24, 2018 12:33 pm

maldus wrote:Thanks again for the hint, I suspected the NVS was not to be trusted in such an extreme scenario.
I test BOD isr to save some data in RAM RTC_NOINIT after remove completely power supply. My longer test is 2 hours and data still live! This is very useful if you just need to keep data in battery replace or home eletric oscillate...

chefotm
Posts: 5
Joined: Thu Apr 05, 2018 6:14 am

Re: Brownout Detection Interrupt

Postby chefotm » Tue Sep 04, 2018 1:30 pm

You can save the data to flash using low level library to custom address. Im using spi_flash_write(ADDRESS, DATA_TO_WRITE, DATA_SIZE); . But you must have erased the selected region to 0xFF. (im using spi_flash_erase_range(ADDRESS, LENGTH); ). You can not erase the sector in brownout because of time difficulty of that operation. Just one note. You must use the highest brownout level (BROWNOUT_DET_LVL 7 and CONFIG_BROWNOUT_DET_LVL_SEL_7 1).

snahmad75
Posts: 445
Joined: Wed Jan 24, 2018 6:32 pm

Re: Brownout Detection Interrupt

Postby snahmad75 » Thu Feb 21, 2019 2:52 pm

I need to detect brownout early. I manage to check my GPIO pin if goes down which is working for me.

I will stop any writing to SD card. but I also need to stop Wifi as well. how can I do Wifi stop. Is there any method.

vishal.borle
Posts: 13
Joined: Thu May 07, 2020 1:32 pm

Re: Brownout Detection Interrupt

Postby vishal.borle » Mon Apr 26, 2021 3:56 pm

I want to do same If power failing detect BOD and store one value in flash. How I can do it this possinle using NVS.

I am tring but still not able to store value when BOD happen.

Who is online

Users browsing this forum: No registered users and 101 guests