#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"
* 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();
}
--- /dev/null
+// 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
#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.
*/
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.
*
*/
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.
*
#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
#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"
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()
#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();
}
}
#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 ");
return;
}
panicPutStr(". Exception was unhandled.\r\n");
+ esp_reset_reason_set_hint(ESP_RST_PANIC);
}
commonErrorHandler(frame);
}
--- /dev/null
+// 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;
+}
#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";
#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) ({ \
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();
}