ESP32 reset itself after pressing button on EDGENT

I’m migrating my project to using Edgent for the next stage of development. Right now, I’m facing issue with using the reset button to trigger other actions in my code when I’m trying to use Edgent. Some info about my project:

  • Custom designed ESP32 board, using ESP32-WROOM-32E
  • Blynk library: 1.1.0

Here’s my main code:

// Fill-in information from your Blynk Template here
#define BLYNK_TEMPLATE_ID "TMPLMTq2KSTq"
#define BLYNK_DEVICE_NAME "TEST1"

#define BLYNK_FIRMWARE_VERSION        "0.5.2"

#define BLYNK_PRINT Serial
//#define BLYNK_DEBUG

#define APP_DEBUG

// Uncomment your board, or configure a custom board in Settings.h
//#define USE_WROVER_BOARD
//#define USE_TTGO_T7
//#define USE_ESP32C3_DEV_MODULE
//#define USE_ESP32S2_DEV_KIT

#include "BlynkEdgent.h"

bool trainingState = false;

//V2 is the button for switching training mode, toggle the training state when its pushed
BLYNK_WRITE(V2) {
  trainingState = param.asInt();   //store the value from the app/console button state
  g_toggle = trainingState;
  digitalWrite(LED_MIRROR, trainingState);    //switch off the Mirror led

  if (trainingState == 1) {
    Blynk.virtualWrite(V3, "Training A");
  }
  else {
    Blynk.virtualWrite(V3, "Training B");
  }
}

/////////////////////////// SETUP ////////////////////////////////////
void setup() {
  Serial.begin(115200);
  delay(100);

  pinMode(LED_MIRROR, OUTPUT);

  BlynkEdgent.begin();
}
//////////////////////////// END OF SETUP ///////////////////////////////


///////////////// MAIN PROGRAM LOOP ///////////////////////////
void loop() {
  BlynkEdgent.run();
  digitalWrite(LED_MIRROR, g_toggle);
}

And here’s the modified ResetButton.h:

#ifdef BOARD_BUTTON_PIN

volatile bool     g_buttonPressed = false;
volatile uint32_t g_buttonPressTime = -1;
volatile bool     g_toggle = false;

void button_action(void)
{
  BlynkState::set(MODE_RESET_CONFIG);
}

void button_change(void)
{
#if BOARD_BUTTON_ACTIVE_LOW
  bool buttonState = !digitalRead(BOARD_BUTTON_PIN);
#else
  bool buttonState = digitalRead(BOARD_BUTTON_PIN);
#endif

  if (buttonState && !g_buttonPressed) {
    g_buttonPressTime = millis();
    g_buttonPressed = true;
    DEBUG_PRINT("Hold the button for 10 seconds to reset configuration...");
  } else if (!buttonState && g_buttonPressed) {
    g_buttonPressed = false;
    uint32_t buttonHoldTime = millis() - g_buttonPressTime;
    if (buttonHoldTime >= BUTTON_HOLD_TIME_ACTION) {
      button_action();
    } else if (buttonHoldTime >= BUTTON_PRESS_TIME_ACTION) {
      // User action
      g_toggle = !g_toggle;
      Blynk.virtualWrite(V2, g_toggle);
    }
    g_buttonPressTime = -1;
  }
}

void button_init()
{
#if BOARD_BUTTON_ACTIVE_LOW
  pinMode(BOARD_BUTTON_PIN, INPUT_PULLUP);
#else
  pinMode(BOARD_BUTTON_PIN, INPUT_PULLDOWN);
#endif
  attachInterrupt(BOARD_BUTTON_PIN, button_change, CHANGE);
}

#else

#define g_buttonPressed     false
#define g_buttonPressTime   0

void button_init() {}

#endif

Now everytime when I pressed the button, the ESP32 will reset itself. Here’s the debug message from serial monitor:

15:56:09.952 -> rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
15:56:09.952 -> configsip: 0, SPIWP:0xee
15:56:09.952 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
15:56:09.952 -> mode:DIO, clock div:1
15:56:09.952 -> load:0x3fff0030,len:1344
15:56:09.952 -> load:0x40078000,len:13864
15:56:09.952 -> load:0x40080400,len:3608
15:56:09.952 -> entry 0x400805f0
15:56:10.512 -> [228] 
15:56:10.512 ->     ___  __          __
15:56:10.512 ->    / _ )/ /_ _____  / /__
15:56:10.512 ->   / _  / / // / _ \/  '_/
15:56:10.512 ->  /____/_/\_, /_//_/_/\_\
15:56:10.512 ->         /___/ v1.1.0 on ESP32
15:56:10.512 -> 
15:56:10.512 ->  #StandWithUkraine    https://bit.ly/swua
15:56:10.512 -> 
15:56:10.512 -> 
15:56:10.512 -> [239] --------------------------
15:56:10.512 -> [239] Product:  TEST1
15:56:10.512 -> [249] Firmware: 0.5.2 (build Dec 22 2022 15:55:03)
15:56:10.512 -> [249] Token:    ba3Y - •••• - •••• - ••••
15:56:10.512 -> [249] Device:   ESP32 @ 240MHz
15:56:10.512 -> [260] MAC:      C0:49:EF:32:D0:84
15:56:10.512 -> [260] Flash:    4096K
15:56:10.512 -> [260] ESP sdk:  v4.4.2
15:56:10.512 -> [260] Chip rev: 3
15:56:10.512 -> [271] Free mem: 238712
15:56:10.512 -> [271] --------------------------
15:56:10.512 -> 
15:56:10.512 -> >[271] INIT => CONNECTING_NET
15:56:10.512 -> [271] Connecting to WiFi: HOMEWIFI
15:57:00.514 -> [50289] Connecting to WiFi: HOMEWIFI
15:57:02.657 -> [52434] Using Dynamic IP: 192.168.0.8
15:57:02.657 -> [52434] CONNECTING_NET => CONNECTING_CLOUD
15:57:02.657 -> [52444] Connecting to blynk.cloud:443
15:57:03.726 -> [53474] Certificate OK
15:57:03.726 -> [53506] Ready (ping: 30ms).
15:57:03.820 -> [53574] CONNECTING_CLOUD => RUNNING
15:57:07.905 -> [57650] Hold the button for 10 seconds to reset configuration...
15:57:08.417 -> Guru Meditation Error: Core  0 panic'ed (Interrupt wdt timeout on CPU0). 
15:57:08.417 -> 
15:57:08.417 -> Core  0 register dump:
15:57:08.417 -> PC      : 0x4009050b  PS      : 0x00060635  A0      : 0x8008fbf3  A1      : 0x3ffb32e0  
15:57:08.417 -> A2      : 0x3ffbf188  A3      : 0xb33fffff  A4      : 0x0000abab  A5      : 0x00060623  
15:57:08.417 -> A6      : 0x00060623  A7      : 0x0000cdcd  A8      : 0x0000abab  A9      : 0xffffffff  
15:57:08.417 -> A10     : 0x3ffbea14  A11     : 0x3ffb342c  A12     : 0x00000097  A13     : 0x0000e186  
15:57:08.417 -> A14     : 0x007bf188  A15     : 0x003fffff  SAR     : 0x00000020  EXCCAUSE: 0x00000005  
15:57:08.464 -> EXCVADDR: 0x00000000  LBEG    : 0x40089988  LEND    : 0x4008999e  LCOUNT  : 0xffffffff  
15:57:08.464 -> 
15:57:08.464 -> 
15:57:08.464 -> Backtrace:0x40090508:0x3ffb32e00x4008fbf0:0x3ffb3320 0x4008d9e6:0x3ffb3340 0x4008de7e:0x3ffb3360 0x4010812a:0x3ffb33a0 0x40108442:0x3ffb33c0 0x40109697:0x3ffb33e0 0x4010adb5:0x3ffb3400 0x400f8ef3:0x3ffb3420 
15:57:08.464 -> 
15:57:08.464 -> 
15:57:08.464 -> Core  1 register dump:
15:57:08.464 -> PC      : 0x4009038a  PS      : 0x00060b35  A0      : 0x8008f0aa  A1      : 0x3ffbe91c  
15:57:08.464 -> A2      : 0x3ffcfb04  A3      : 0x3ffb8890  A4      : 0x00000004  A5      : 0x00060b23  
15:57:08.509 -> A6      : 0x00060b23  A7      : 0x00000001  A8      : 0x3ffb8890  A9      : 0x00000018  
15:57:08.509 -> A10     : 0x3ffb8890  A11     : 0x00000018  A12     : 0x3ffc557c  A13     : 0x00060b23  
15:57:08.509 -> A14     : 0x007bf188  A15     : 0x003fffff  SAR     : 0x00000018  EXCCAUSE: 0x00000005  
15:57:08.509 -> EXCVADDR: 0x00000000  LBEG    : 0x40089988  LEND    : 0x4008999e  LCOUNT  : 0xffffffff  
15:57:08.509 -> 
15:57:08.509 -> 
15:57:08.509 -> Backtrace:0x40090387:0x3ffbe91c |<-CORRUPTED
15:57:08.509 -> 
15:57:08.509 -> 
15:57:08.509 -> 
15:57:08.509 -> 
15:57:08.509 -> ELF file SHA256: 0000000000000000
15:57:08.509 -> 
15:57:08.509 -> Rebooting...
15:57:08.556 -> ets Jul 29 2019 12:21:46
15:57:08.556 -> 

I’m guessing I can’t use Blynk.virtualWrite() in the ISR. But why?

when you say “reset button” exactly which button are you referring to? I guess that as this is your custom board, the real question is what is this reset button connected to?

Most standard ESP32 dev boards have two buttons, one is labeled RST or EN and is connected to GND and the EN pin on the chip. The other is connected to either GND or Vcc (it depends on the board design) and the GPIO0 pin on the chip and is usually labelled BOOT.

Pressing the RST/EN button will always reboot the board. That is a low-level function of the chip and can’t be overridden in code.

If you’re using a button that’s not connected to the EN pin on the chip then you should provide details about whether one side of the button is connected to GND or Vcc, and confirm that the other side os connected to GPIO0. You should also share the custom board settings section of your Settings.h file, as you haven’t un-commented any of the pre-defined board types in the sketch.

also, this isn’t good practice…

Pete.

I only have one single button on my custom board, it’s connected to GPIO23 which will connect the GPIO to the ground when it is pressed. By the way, I’m using the ESP32-WROOM-32E for my custom board, updated that info in my original post too.

My bad, here’s the Settings.h :


/*
 * Board configuration (see examples below).
 */

#if defined(USE_WROVER_BOARD)

  #define BOARD_BUTTON_PIN            15
  #define BOARD_BUTTON_ACTIVE_LOW     true

  #define BOARD_LED_PIN_R             0
  #define BOARD_LED_PIN_G             2
  #define BOARD_LED_PIN_B             4
  #define BOARD_LED_INVERSE           false
  #define BOARD_LED_BRIGHTNESS        128

#elif defined(USE_TTGO_T7)

  // This board does not have a built-in button
  // Connect a button to gpio0 <> GND
  #define BOARD_BUTTON_PIN            0
  #define BOARD_BUTTON_ACTIVE_LOW     true

  #define BOARD_LED_PIN               19
  #define BOARD_LED_INVERSE           false
  #define BOARD_LED_BRIGHTNESS        64

#elif defined(USE_ESP32C3_DEV_MODULE)

  #define BOARD_BUTTON_PIN            9
  #define BOARD_BUTTON_ACTIVE_LOW     true

  #define BOARD_LED_PIN_WS2812        8
  #define BOARD_LED_INVERSE           false
  #define BOARD_LED_BRIGHTNESS        32

#elif defined(USE_ESP32S2_DEV_KIT)

  #define BOARD_BUTTON_PIN            0
  #define BOARD_BUTTON_ACTIVE_LOW     true

  #define BOARD_LED_PIN               19
  #define BOARD_LED_INVERSE           false
  #define BOARD_LED_BRIGHTNESS        128

#else

  #warning "Custom board configuration is used"

  #define BOARD_BUTTON_PIN            23                     // Pin where user button is attached
  #define BOARD_BUTTON_ACTIVE_LOW     true        // true if button is "active-low"

  #define BOARD_LED_PIN               22           // Set LED pin - if you have a single-color LED attached
  #define LED_MIRROR                  21              // LED indicator for MIRROR TRAINING
  //#define BOARD_LED_PIN_R           15       // Set R,G,B pins - if your LED is PWM RGB
  //#define BOARD_LED_PIN_G           12
  //#define BOARD_LED_PIN_B           13
  //#define BOARD_LED_PIN_WS2812      4      // Set if your LED is WS2812 RGB
  #define BOARD_LED_INVERSE           false   // true if LED is common anode, false if common cathode
  #define BOARD_LED_BRIGHTNESS        255                    // 0..255 brightness control

#endif


/*
 * Advanced options
 */

#define BUTTON_HOLD_TIME_INDICATION   3000
#define BUTTON_HOLD_TIME_ACTION       10000
#define BUTTON_PRESS_TIME_ACTION      50

#define BOARD_PWM_MAX                 1023

#define BOARD_LEDC_CHANNEL_1          1
#define BOARD_LEDC_CHANNEL_2          2
#define BOARD_LEDC_CHANNEL_3          3
#define BOARD_LEDC_TIMER_BITS         10
#define BOARD_LEDC_BASE_FREQ          12000

#if !defined(CONFIG_DEVICE_PREFIX)
#define CONFIG_DEVICE_PREFIX          "Blynk"
#endif
#if !defined(CONFIG_AP_URL)
#define CONFIG_AP_URL                 "blynk.setup"
#endif
#if !defined(CONFIG_DEFAULT_SERVER)
#define CONFIG_DEFAULT_SERVER         "blynk.cloud"
#endif
#if !defined(CONFIG_DEFAULT_PORT)
#define CONFIG_DEFAULT_PORT           443
#endif

#define WIFI_CLOUD_MAX_RETRIES        500
#define WIFI_NET_CONNECT_TIMEOUT      50000
#define WIFI_CLOUD_CONNECT_TIMEOUT    50000
#define WIFI_AP_IP                    IPAddress(192, 168, 4, 1)
#define WIFI_AP_Subnet                IPAddress(255, 255, 255, 0)
//#define WIFI_CAPTIVE_PORTAL_ENABLE

//#define USE_TICKER
//#define USE_TIMER_ONE
//#define USE_TIMER_THREE
//#define USE_TIMER_FIVE
#define USE_PTHREAD

#define BLYNK_NO_DEFAULT_BANNER

#if defined(APP_DEBUG)
  #define DEBUG_PRINT(...)  BLYNK_LOG1(__VA_ARGS__)
  #define DEBUG_PRINTF(...) BLYNK_LOG(__VA_ARGS__)
#else
  #define DEBUG_PRINT(...)
  #define DEBUG_PRINTF(...)
#endif

Why? Anyway, I’m not too sure how should I toggle the LED yet in the Indicator.h, I have 2 LEDs which should be toggled ON/OFF whenever the button is being pressed.

The value of g_toggle is going to change very rarely, yet you’re writing its value to the LED_MIRROR pin thousands of times each second for the whole time that the board id running.
While the processor is performing this unnecessary action its not doing anything else.
It’s sloppy, and bad practice.

It certainly breaks the “lean and mean” rule of ISR coding. Have you tried to decode the register dump top get some pointers?

Pete.

Hmm, you’re right. Didn’t think about that. Will change that, but as of now it serves the purpose to proof my idea that I can call g_toggle anywhere.

No, I’m not quite sure what are those too. My focus now is to find out how should I sync the physical button with the web console button in the Edgent code base, without causing any other issue.

What exactly is it that you are trying to achieve?

Pete.

There’s 2 LED on my board, which should indicate what mode my device is in, lets call it Mode A and Mode B without going too much into the specifics. Whenever the user pressed the button, the device will switch into another mode (Ex. A > B or vice versa). The LED will also change at the same time when the user pressed the button.

In my web console, I also have a button widget that should sync up with the physical device’s button to show which mode it is in. The thing I’m trying to achieve now is to sync up the physical device’s button state with the button widget on the web console.

The reason I’m using Edgent is because we are planning to deploy the product in the later stage into the market, which will allow the user to self-configure the wifi credentials. (And also the very cool OTA update for us to continuously update the device’s firmware :smile:)