Jelajahi Sumber

esp32s2beta: implement esp_reset_reason API

Ivan Grokhotkov 6 tahun lalu
induk
melakukan
ea99137e62

+ 1 - 0
components/esp32s2beta/CMakeLists.txt

@@ -26,6 +26,7 @@ else()
              "panic.c"
              "pm_esp32s2beta.c"
              "pm_trace.c"
+             "reset_reason.c"
              "sleep_modes.c"
              "spiram.c"
              "spiram_psram.c"

+ 25 - 0
components/esp32s2beta/panic.c

@@ -123,6 +123,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(void)
@@ -149,6 +163,12 @@ void abort(void)
 #if !CONFIG_ESP32S2_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();
 }
 
@@ -326,6 +346,10 @@ void panicHandler(XtExcFrame *frame)
     }
 #endif //!CONFIG_FREERTOS_UNICORE
 
+    if (frame->exccause == PANIC_RSN_INTWDT_CPU0) {
+        esp_reset_reason_set_hint(ESP_RST_INT_WDT);
+    }
+
     haltOtherCore();
     panicPutStr("Guru Meditation Error: Core ");
     panicPutDec(core_id);
@@ -428,6 +452,7 @@ void xt_unhandled_exception(XtExcFrame *frame)
         }
 #endif
         panicPutStr(". Exception was unhandled.\r\n");
+        esp_reset_reason_set_hint(ESP_RST_PANIC);
     }
     commonErrorHandler(frame);
 }

+ 123 - 0
components/esp32s2beta/reset_reason.c

@@ -0,0 +1,123 @@
+// 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 "esp32s2beta/rom/rtc.h"
+#include "esp_private/system_internal.h"
+#include "soc/rtc_periph.h"
+
+static void esp_reset_reason_clear_hint(void);
+
+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;
+
+        case RTC_SW_CPU_RESET:
+        case RTC_SW_SYS_RESET:
+            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 RTCWDT_SYS_RESET:
+        case RTCWDT_RTC_RESET:
+        case SUPER_WDT_RESET:
+        case RTCWDT_CPU_RESET:  /* unused */
+        case TG0WDT_CPU_RESET:   /* unused */
+        case TG1WDT_CPU_RESET:   /* unused */
+            return ESP_RST_WDT;
+
+        case RTCWDT_BROWN_OUT_RESET:
+            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)
+{
+    esp_reset_reason_t hint = esp_reset_reason_get_hint();
+    s_reset_reason = get_reset_reason(rtc_get_reset_reason(PRO_CPU_NUM),
+                                      hint);
+    if (hint != ESP_RST_UNKNOWN) {
+        esp_reset_reason_clear_hint();
+    }
+}
+
+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;
+}
+static void esp_reset_reason_clear_hint(void)
+{
+    REG_WRITE(RTC_RESET_CAUSE_REG, 0);
+}
+

+ 1 - 2
components/esp32s2beta/task_wdt.c

@@ -168,8 +168,7 @@ static void task_wdt_isr(void *arg)
     if (twdt_config->panic){     //Trigger Panic if configured to do so
         ESP_EARLY_LOGE(TAG, "Aborting.");
         portEXIT_CRITICAL_ISR(&twdt_spinlock);
-        // TODO: Add support reset reason for esp32s2beta.
-        // esp_reset_reason_set_hint(ESP_RST_TASK_WDT);
+        esp_reset_reason_set_hint(ESP_RST_TASK_WDT);
         abort();
     }
 

+ 1 - 0
components/esp_rom/include/esp32s2beta/rom/rtc.h

@@ -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