From ea99137e6240903c7f8dcf062694975df4bb90a7 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 19 Nov 2019 11:19:29 +0100 Subject: [PATCH] esp32s2beta: implement esp_reset_reason API --- components/esp32s2beta/CMakeLists.txt | 1 + components/esp32s2beta/panic.c | 25 ++++ components/esp32s2beta/reset_reason.c | 123 ++++++++++++++++++ components/esp32s2beta/task_wdt.c | 3 +- .../esp_rom/include/esp32s2beta/rom/rtc.h | 1 + 5 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 components/esp32s2beta/reset_reason.c diff --git a/components/esp32s2beta/CMakeLists.txt b/components/esp32s2beta/CMakeLists.txt index f0d46758b7..1892720ed1 100644 --- a/components/esp32s2beta/CMakeLists.txt +++ b/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" diff --git a/components/esp32s2beta/panic.c b/components/esp32s2beta/panic.c index 0082e0a85e..5dd20615da 100644 --- a/components/esp32s2beta/panic.c +++ b/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); } diff --git a/components/esp32s2beta/reset_reason.c b/components/esp32s2beta/reset_reason.c new file mode 100644 index 0000000000..1ed5bb765c --- /dev/null +++ b/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); +} + diff --git a/components/esp32s2beta/task_wdt.c b/components/esp32s2beta/task_wdt.c index e8ca2f7730..cd562e3b75 100644 --- a/components/esp32s2beta/task_wdt.c +++ b/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(); } diff --git a/components/esp_rom/include/esp32s2beta/rom/rtc.h b/components/esp_rom/include/esp32s2beta/rom/rtc.h index 3406eab33b..c46c9c1f56 100644 --- a/components/esp_rom/include/esp32s2beta/rom/rtc.h +++ b/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