]> granicus.if.org Git - esp-idf/commitdiff
esp32: add API to get reset reason
authorIvan Grokhotkov <ivan@espressif.com>
Sun, 29 Jul 2018 09:57:59 +0000 (12:57 +0300)
committerIvan Grokhotkov <ivan@espressif.com>
Mon, 20 Aug 2018 08:49:20 +0000 (16:49 +0800)
components/esp32/brownout.c
components/esp32/esp_system_internal.h [new file with mode: 0644]
components/esp32/include/esp_system.h
components/esp32/include/rom/rtc.h
components/esp32/panic.c
components/esp32/reset_reason.c [new file with mode: 0644]
components/esp32/system_api.c
components/esp32/task_wdt.c

index 50d8ac04420135dc1f16e2de9d3325be7d02b09e..1d78006140c3b820a288df12532729bcceb63daf 100644 (file)
@@ -21,7 +21,7 @@
 #include "soc/cpu.h"
 #include "soc/rtc_cntl_reg.h"
 #include "rom/ets_sys.h"
-#include "esp_system.h"
+#include "esp_system_internal.h"
 #include "driver/rtc_cntl.h"
 #include "freertos/FreeRTOS.h"
 
@@ -42,6 +42,7 @@ static void rtc_brownout_isr_handler()
      * at the same time as the following ets_printf.
      */
     esp_cpu_stall(!xPortGetCoreID());
+    esp_reset_reason_set_hint(ESP_RST_BROWNOUT);
     ets_printf("\r\nBrownout detector was triggered\r\n\r\n");
     esp_restart_noos();
 }
diff --git a/components/esp32/esp_system_internal.h b/components/esp32/esp_system_internal.h
new file mode 100644 (file)
index 0000000..5bda73f
--- /dev/null
@@ -0,0 +1,56 @@
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "esp_system.h"
+
+/**
+ * @brief  Internal function to restart PRO and APP CPUs.
+ *
+ * @note This function should not be called from FreeRTOS applications.
+ *       Use esp_restart instead.
+ *
+ * This is an internal function called by esp_restart. It is called directly
+ * by the panic handler and brownout detector interrupt.
+ */
+void esp_restart_noos() __attribute__ ((noreturn));
+
+/**
+ * @brief  Internal function to set reset reason hint
+ *
+ * The hint is used do distinguish different reset reasons when software reset
+ * is performed.
+ *
+ * The hint is stored in RTC store register, RTC_RESET_CAUSE_REG.
+ *
+ * @param hint  Desired esp_reset_reason_t value for the real reset reason
+ */
+void esp_reset_reason_set_hint(esp_reset_reason_t hint);
+
+/**
+ * @brief  Internal function to get the reset hint value
+ * @return  - Reset hint value previously stored into RTC_RESET_CAUSE_REG using
+ *          esp_reset_reason_set_hint function
+ *          - ESP_RST_UNKNOWN if the value in RTC_RESET_CAUSE_REG is invalid
+ */
+esp_reset_reason_t esp_reset_reason_get_hint(void);
+
+#ifdef __cplusplus
+}
+#endif
index 0d57d84d842d6b51c4c3314803ab5ba4003c04fc..01feea32d2e5ae7796c13cc7c46291db45f7fffb 100644 (file)
@@ -35,6 +35,25 @@ typedef enum {
 #define FOUR_UNIVERSAL_MAC_ADDR 4
 #define UNIVERSAL_MAC_ADDR_NUM CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS
 
+
+/**
+ * @brief Reset reasons
+ */
+typedef enum {
+    ESP_RST_UNKNOWN,    //!< Reset reason can not be determined
+    ESP_RST_POWERON,    //!< Reset due to power-on event
+    ESP_RST_EXT,        //!< Reset by external pin (not applicable for ESP32)
+    ESP_RST_SW,         //!< Software reset via esp_restart
+    ESP_RST_PANIC,      //!< Software reset due to exception/panic
+    ESP_RST_INT_WDT,    //!< Reset (software or hardware) due to interrupt watchdog
+    ESP_RST_TASK_WDT,   //!< Reset due to task watchdog
+    ESP_RST_WDT,        //!< Reset due to other watchdogs
+    ESP_RST_DEEPSLEEP,  //!< Reset after exiting deep sleep mode
+    ESP_RST_BROWNOUT,   //!< Brownout reset (software or hardware)
+    ESP_RST_SDIO,       //!< Reset over SDIO
+} esp_reset_reason_t;
+
+/** @cond */
 /**
   * @attention  application don't need to call this function anymore. It do nothing and will
   *             be removed in future version.
@@ -68,17 +87,6 @@ esp_err_t esp_register_shutdown_handler(shutdown_handler_t handle);
   */
 void esp_restart(void) __attribute__ ((noreturn));
 
-/**
-  * @brief  Internal function to restart PRO and APP CPUs.
-  *
-  * @note This function should not be called from FreeRTOS applications.
-  *       Use esp_restart instead.
-  *
-  * This is an internal function called by esp_restart. It is called directly
-  * by the panic handler and brownout detector interrupt.
-  */
-void esp_restart_noos() __attribute__ ((noreturn));
-
 /**
   * @brief  Restart system.
   *
@@ -87,6 +95,12 @@ void esp_restart_noos() __attribute__ ((noreturn));
   */
 void system_restart(void) __attribute__ ((deprecated, noreturn));
 
+/**
+ * @brief  Get reason of last reset
+ * @return See description of esp_reset_reason_t for explanation of each value.
+ */
+esp_reset_reason_t esp_reset_reason(void);
+
 /**
   * @brief  Get system time, unit: microsecond.
   *
index 08d8ace09426344376e3c41756d99a4afaaef7bb..9ebd1020b5c895f539d0c16f5bf4f5a552269c09 100644 (file)
@@ -68,6 +68,7 @@ extern "C" {
 #define RTC_XTAL_FREQ_REG       RTC_CNTL_STORE4_REG
 #define RTC_APB_FREQ_REG        RTC_CNTL_STORE5_REG
 #define RTC_ENTRY_ADDR_REG      RTC_CNTL_STORE6_REG
+#define RTC_RESET_CAUSE_REG     RTC_CNTL_STORE6_REG
 #define RTC_MEMORY_CRC_REG      RTC_CNTL_STORE7_REG
 
 
index 5a000574be081b3044b44eba7fcb06928fd87ec1..e8640c02561432f2c95a1e7b21108168f0b80a91 100644 (file)
@@ -40,7 +40,7 @@
 #include "esp_spi_flash.h"
 #include "esp_cache_err_int.h"
 #include "esp_app_trace.h"
-#include "esp_system.h"
+#include "esp_system_internal.h"
 #include "sdkconfig.h"
 #if CONFIG_SYSVIEW_ENABLE
 #include "SEGGER_RTT.h"
@@ -121,6 +121,20 @@ void  __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, s
     abort();
 }
 
+/* These two weak stubs for esp_reset_reason_{get,set}_hint are used when
+ * the application does not call esp_reset_reason() function, and
+ * reset_reason.c is not linked into the output file.
+ */
+void __attribute__((weak)) esp_reset_reason_set_hint(esp_reset_reason_t hint)
+{
+}
+
+esp_reset_reason_t __attribute__((weak)) esp_reset_reason_get_hint(void)
+{
+    return ESP_RST_UNKNOWN;
+}
+
+
 static bool abort_called;
 
 static __attribute__((noreturn)) inline void invoke_abort()
@@ -147,6 +161,12 @@ void abort()
 #if !CONFIG_ESP32_PANIC_SILENT_REBOOT
     ets_printf("abort() was called at PC 0x%08x on core %d\r\n", (intptr_t)__builtin_return_address(0) - 3, xPortGetCoreID());
 #endif
+    /* Calling code might have set other reset reason hint (such as Task WDT),
+     * don't overwrite that.
+     */
+    if (esp_reset_reason_get_hint() == ESP_RST_UNKNOWN) {
+        esp_reset_reason_set_hint(ESP_RST_PANIC);
+    }
     invoke_abort();
 }
 
@@ -234,6 +254,10 @@ void panicHandler(XtExcFrame *frame)
     }
 #endif //!CONFIG_FREERTOS_UNICORE
 
+    if (frame->exccause == PANIC_RSN_INTWDT_CPU0 || frame->exccause == PANIC_RSN_INTWDT_CPU1) {
+        esp_reset_reason_set_hint(ESP_RST_INT_WDT);
+    }
+
     haltOtherCore();
     esp_dport_access_int_abort();
     panicPutStr("Guru Meditation Error: Core ");
@@ -333,6 +357,7 @@ void xt_unhandled_exception(XtExcFrame *frame)
             return;
         }
         panicPutStr(". Exception was unhandled.\r\n");
+        esp_reset_reason_set_hint(ESP_RST_PANIC);
     }
     commonErrorHandler(frame);
 }
diff --git a/components/esp32/reset_reason.c b/components/esp32/reset_reason.c
new file mode 100644 (file)
index 0000000..191271d
--- /dev/null
@@ -0,0 +1,116 @@
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "esp_system.h"
+#include "esp_system_internal.h"
+#include "rom/rtc.h"
+#include "soc/rtc_cntl_reg.h"
+
+static esp_reset_reason_t s_reset_reason;
+
+static esp_reset_reason_t get_reset_reason(RESET_REASON rtc_reset_reason, esp_reset_reason_t reset_reason_hint)
+{
+    switch (rtc_reset_reason) {
+        case POWERON_RESET:
+            return ESP_RST_POWERON;
+
+        /* For ESP32, ESP_RST_EXT is never returned */
+
+
+        case SW_CPU_RESET:
+        case SW_RESET:
+        case EXT_CPU_RESET: /* unused */
+            if (reset_reason_hint == ESP_RST_PANIC ||
+                reset_reason_hint == ESP_RST_BROWNOUT ||
+                reset_reason_hint == ESP_RST_TASK_WDT ||
+                reset_reason_hint == ESP_RST_INT_WDT) {
+                return reset_reason_hint;
+            }
+            return ESP_RST_SW;
+
+        case DEEPSLEEP_RESET:
+            return ESP_RST_DEEPSLEEP;
+
+        case TG0WDT_SYS_RESET:
+            return ESP_RST_TASK_WDT;
+
+        case TG1WDT_SYS_RESET:
+            return ESP_RST_INT_WDT;
+
+        case OWDT_RESET:
+        case RTCWDT_SYS_RESET:
+        case RTCWDT_RTC_RESET:
+        case RTCWDT_CPU_RESET:  /* unused */
+        case TGWDT_CPU_RESET:   /* unused */
+            return ESP_RST_WDT;
+
+        case RTCWDT_BROWN_OUT_RESET:    /* unused */
+            return ESP_RST_BROWNOUT;
+
+        case SDIO_RESET:
+            return ESP_RST_SDIO;
+
+        case INTRUSION_RESET: /* unused */
+        default:
+            return ESP_RST_UNKNOWN;
+    }
+}
+
+static void __attribute__((constructor)) esp_reset_reason_init(void)
+{
+    s_reset_reason = get_reset_reason(rtc_get_reset_reason(PRO_CPU_NUM),
+                                      esp_reset_reason_get_hint());
+    esp_reset_reason_set_hint(ESP_RST_UNKNOWN);
+}
+
+esp_reset_reason_t esp_reset_reason(void)
+{
+    return s_reset_reason;
+}
+
+/* Reset reason hint is stored in RTC_RESET_CAUSE_REG, a.k.a. RTC_CNTL_STORE6_REG,
+ * a.k.a. RTC_ENTRY_ADDR_REG. It is safe to use this register both for the
+ * deep sleep wake stub entry address and for reset reason hint, since wake stub
+ * is only used for deep sleep reset, and in this case the reason provided by
+ * rtc_get_reset_reason is unambiguous.
+ *
+ * Same layout is used as for RTC_APB_FREQ_REG (a.k.a. RTC_CNTL_STORE5_REG):
+ * the value is replicated in low and high half-words. In addition to that,
+ * MSB is set to 1, which doesn't happen when RTC_CNTL_STORE6_REG contains
+ * deep sleep wake stub address.
+ */
+
+#define RST_REASON_BIT  0x80000000
+#define RST_REASON_MASK 0x7FFF
+#define RST_REASON_SHIFT 16
+
+/* in IRAM, can be called from panic handler */
+void IRAM_ATTR esp_reset_reason_set_hint(esp_reset_reason_t hint)
+{
+    assert((hint & (~RST_REASON_MASK)) == 0);
+    uint32_t val = hint | (hint << RST_REASON_SHIFT) | RST_REASON_BIT;
+    REG_WRITE(RTC_RESET_CAUSE_REG, val);
+}
+
+/* in IRAM, can be called from panic handler */
+esp_reset_reason_t IRAM_ATTR esp_reset_reason_get_hint(void)
+{
+    uint32_t reset_reason_hint = REG_READ(RTC_RESET_CAUSE_REG);
+    uint32_t high = (reset_reason_hint >> RST_REASON_SHIFT) & RST_REASON_MASK;
+    uint32_t low = reset_reason_hint & RST_REASON_MASK;
+    if ((reset_reason_hint & RST_REASON_BIT) == 0 || high != low) {
+        return ESP_RST_UNKNOWN;
+    }
+    return (esp_reset_reason_t) low;
+}
index f56bf622e2c0b5eae2c9852336f7044a5b0c66a0..ce111bd5966d81423c41150fcd5e28fe05e36f50 100644 (file)
@@ -36,6 +36,7 @@
 #include "freertos/task.h"
 #include "freertos/xtensa_api.h"
 #include "esp_heap_caps.h"
+#include "esp_system_internal.h"
 
 static const char* TAG = "system_api";
 
index 0e0b87c658f9a5db4b849d32a4f041e9952baeb9..fb10aac05e66f0dae4e3fe38d3e1db66721a8529 100644 (file)
@@ -35,6 +35,7 @@
 #include "driver/timer.h"
 #include "driver/periph_ctrl.h"
 #include "esp_task_wdt.h"
+#include "esp_system_internal.h"
 
 //Assertion macro where, if 'cond' is false, will exit the critical section and return 'ret'
 #define ASSERT_EXIT_CRIT_RETURN(cond, ret)  ({                              \
@@ -155,6 +156,7 @@ static void task_wdt_isr(void *arg)
     if (twdt_config->panic){     //Trigger Panic if configured to do so
         ets_printf("Aborting.\n");
         portEXIT_CRITICAL(&twdt_spinlock);
+        esp_reset_reason_set_hint(ESP_RST_TASK_WDT);
         abort();
     }