فهرست منبع

Merge branch 'feature/panic_wdt' into 'master'

esp32: RWDT is used to reboot system in case of panic handler crash

This branch uses RWDT to reboot system in case of panic handler crash.

See merge request !625

Ivan Grokhotkov 8 سال پیش
والد
کامیت
fd0539b4ba
4فایلهای تغییر یافته به همراه65 افزوده شده و 2 حذف شده
  1. 22 1
      components/esp32/cpu_start.c
  2. 5 0
      components/esp32/include/esp_panic.h
  3. 6 0
      components/esp32/include/soc/rtc_cntl_reg.h
  4. 32 1
      components/esp32/panic.c

+ 22 - 1
components/esp32/cpu_start.c

@@ -55,6 +55,7 @@
 #include "esp_task_wdt.h"
 #include "esp_phy_init.h"
 #include "esp_coexist.h"
+#include "esp_panic.h"
 #include "esp_core_dump.h"
 #include "trax.h"
 
@@ -92,6 +93,11 @@ static const char* TAG = "cpu_start";
 
 void IRAM_ATTR call_start_cpu0()
 {
+#if CONFIG_FREERTOS_UNICORE
+    RESET_REASON rst_reas[1];
+#else
+    RESET_REASON rst_reas[2];
+#endif
     cpu_configure_region_protection();
 
     //Move exception vectors to IRAM
@@ -99,10 +105,25 @@ void IRAM_ATTR call_start_cpu0()
                   "wsr    %0, vecbase\n" \
                   ::"r"(&_init_start));
 
+    rst_reas[0] = rtc_get_reset_reason(0);
+#if !CONFIG_FREERTOS_UNICORE
+    rst_reas[1] = rtc_get_reset_reason(1);
+#endif
+    // from panic handler we can be reset by RWDT or TG0WDT
+    if (rst_reas[0] == RTCWDT_SYS_RESET || rst_reas[0] == TG0WDT_SYS_RESET
+#if !CONFIG_FREERTOS_UNICORE
+        || rst_reas[1] == RTCWDT_SYS_RESET || rst_reas[1] == TG0WDT_SYS_RESET
+#endif
+        ) {
+        // stop wdt in case of any
+        ESP_EARLY_LOGI(TAG, "Stop panic WDT");
+        esp_panic_wdt_stop();
+    }
+
     memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start));
 
     /* Unless waking from deep sleep (implying RTC memory is intact), clear RTC bss */
-    if (rtc_get_reset_reason(0) != DEEPSLEEP_RESET) {
+    if (rst_reas[0] != DEEPSLEEP_RESET) {
         memset(&_rtc_bss_start, 0, (&_rtc_bss_end - &_rtc_bss_start) * sizeof(_rtc_bss_start));
     }
 

+ 5 - 0
components/esp32/include/esp_panic.h

@@ -61,6 +61,11 @@ esp_err_t esp_set_watchpoint(int no, void *adr, int size, int flags);
 void esp_clear_watchpoint(int no);
 
 
+/**
+ * @brief Stops panic WDT
+ */
+void esp_panic_wdt_stop(void);
+
 #endif
 
 #ifdef __cplusplus

+ 6 - 0
components/esp32/include/soc/rtc_cntl_reg.h

@@ -1650,6 +1650,12 @@
 #define RTC_CNTL_WDT_PAUSE_IN_SLP_M  (BIT(7))
 #define RTC_CNTL_WDT_PAUSE_IN_SLP_V  0x1
 #define RTC_CNTL_WDT_PAUSE_IN_SLP_S  7
+/* RTC_CNTL_WDT_STGX : */
+/*description: stage action selection values */
+#define RTC_WDT_STG_SEL_OFF             0
+#define RTC_WDT_STG_SEL_INT             1
+#define RTC_WDT_STG_SEL_RESET_CPU       2
+#define RTC_WDT_STG_SEL_RESET_SYSTEM    3
 
 #define RTC_CNTL_WDTCONFIG1_REG          (DR_REG_RTCCNTL_BASE + 0x90)
 /* RTC_CNTL_WDT_STG0_HOLD : R/W ;bitpos:[31:0] ;default: 32'd128000 ; */

+ 32 - 1
components/esp32/panic.c

@@ -284,11 +284,37 @@ static void disableAllWdts()
     TIMERG0.wdt_wprotect = 0;
     TIMERG1.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
     TIMERG1.wdt_config0.en = 0;
-    TIMERG0.wdt_wprotect = 0;
+    TIMERG1.wdt_wprotect = 0;
 }
 
 #endif
 
+static void esp_panic_wdt_start()
+{
+    if (REG_GET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN)) {
+        return;
+    }
+    WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE);
+    WRITE_PERI_REG(RTC_CNTL_WDTFEED_REG, 1);
+    REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_SYS_RESET_LENGTH, 7);
+    REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_CPU_RESET_LENGTH, 7);
+    REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, RTC_WDT_STG_SEL_RESET_SYSTEM);
+    // 64KB of core dump data (stacks of about 30 tasks) will produce ~85KB base64 data.
+    // @ 115200 UART speed it will take more than 6 sec to print them out.
+    WRITE_PERI_REG(RTC_CNTL_WDTCONFIG1_REG, RTC_CNTL_SLOWCLK_FREQ*7);
+    REG_SET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN);
+    WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0);
+}
+
+void esp_panic_wdt_stop()
+{
+    WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE);
+    WRITE_PERI_REG(RTC_CNTL_WDTFEED_REG, 1);
+    REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, RTC_WDT_STG_SEL_OFF);
+    REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN);
+    WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0);
+}
+
 static inline bool stackPointerIsSane(uint32_t sp)
 {
     return !(sp < 0x3ffae010 || sp > 0x3ffffff0 || ((sp & 0xf) != 0));
@@ -343,6 +369,9 @@ static void commonErrorHandler(XtExcFrame *frame)
         "A14     ", "A15     ", "SAR     ", "EXCCAUSE", "EXCVADDR", "LBEG    ", "LEND    ", "LCOUNT  "
     };
 
+    // start panic WDT to restart system if we hang in this handler
+    esp_panic_wdt_start();
+
     //Feed the watchdogs, so they will give us time to print out debug info
     reconfigureAllWdts();
 
@@ -370,6 +399,7 @@ static void commonErrorHandler(XtExcFrame *frame)
 
 #if CONFIG_ESP32_PANIC_GDBSTUB
     disableAllWdts();
+    esp_panic_wdt_stop();
     panicPutStr("Entering gdb stub now.\r\n");
     esp_gdbstub_panic_handler(frame);
 #else
@@ -383,6 +413,7 @@ static void commonErrorHandler(XtExcFrame *frame)
 #endif
     reconfigureAllWdts();
 #endif
+    esp_panic_wdt_stop();
 #if CONFIG_ESP32_PANIC_PRINT_REBOOT || CONFIG_ESP32_PANIC_SILENT_REBOOT
     panicPutStr("Rebooting...\r\n");
     esp_restart_noos();