Merge branch 'feature/reset_reason' into 'master'

Add API to get reset reason

See merge request idf/esp-idf!2871
This commit is contained in:
Ivan Grokhotkov 2018-08-21 11:34:12 +08:00
commit 4dd7233b20
23 changed files with 620 additions and 287 deletions

View 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();
}

View file

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

View file

@ -31,12 +31,32 @@ typedef enum {
ESP_MAC_ETH,
} esp_mac_type_t;
/** @cond */
#define TWO_UNIVERSAL_MAC_ADDR 2
#define FOUR_UNIVERSAL_MAC_ADDR 4
#define UNIVERSAL_MAC_ADDR_NUM CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS
/** @endcond */
/**
* @attention application don't need to call this function anymore. It do nothing and will
* @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 Applications don't need to call this function anymore. It does nothing and will
* be removed in future version.
*/
void system_init(void) __attribute__ ((deprecated));
@ -48,13 +68,18 @@ void system_init(void) __attribute__ ((deprecated));
* This name will be removed in a future release.
*/
void system_restore(void) __attribute__ ((deprecated));
/** @endcond */
/**
* Shutdown handler type
*/
typedef void (*shutdown_handler_t)(void);
/**
* @brief Register shutdown handler
*
* This function allows you to register a handler that gets invoked before a
* systematic shutdown of the chip.
* This function allows you to register a handler that gets invoked before
* the application is restarted using esp_restart function.
*/
esp_err_t esp_register_shutdown_handler(shutdown_handler_t handle);
@ -68,17 +93,7 @@ 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));
/** @cond */
/**
* @brief Restart system.
*
@ -86,7 +101,15 @@ void esp_restart_noos() __attribute__ ((noreturn));
* This name will be removed in a future release.
*/
void system_restart(void) __attribute__ ((deprecated, noreturn));
/** @endcond */
/**
* @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);
/** @cond */
/**
* @brief Get system time, unit: microsecond.
*
@ -94,6 +117,7 @@ void system_restart(void) __attribute__ ((deprecated, noreturn));
* This definition will be removed in a future release.
*/
uint32_t system_get_time(void) __attribute__ ((deprecated));
/** @endcond */
/**
* @brief Get the size of available heap.
@ -105,6 +129,7 @@ uint32_t system_get_time(void) __attribute__ ((deprecated));
*/
uint32_t esp_get_free_heap_size(void);
/** @cond */
/**
* @brief Get the size of available heap.
*
@ -114,6 +139,7 @@ uint32_t esp_get_free_heap_size(void);
* @return Available heap size, in bytes.
*/
uint32_t system_get_free_heap_size(void) __attribute__ ((deprecated));
/** @endcond */
/**
* @brief Get the minimum heap that has ever been available
@ -187,6 +213,7 @@ esp_err_t esp_efuse_mac_get_custom(uint8_t *mac);
*/
esp_err_t esp_efuse_mac_get_default(uint8_t *mac);
/** @cond */
/**
* @brief Read hardware MAC address from efuse.
*
@ -209,6 +236,7 @@ esp_err_t esp_efuse_read_mac(uint8_t *mac) __attribute__ ((deprecated));
* @return ESP_OK on success
*/
esp_err_t system_efuse_read_mac(uint8_t *mac) __attribute__ ((deprecated));
/** @endcond */
/**
* @brief Read base MAC address and set MAC address of the interface.
@ -240,6 +268,7 @@ esp_err_t esp_read_mac(uint8_t* mac, esp_mac_type_t type);
*/
esp_err_t esp_derive_local_mac(uint8_t* local_mac, const uint8_t* universal_mac);
/** @cond */
/**
* Get SDK version
*
@ -248,6 +277,7 @@ esp_err_t esp_derive_local_mac(uint8_t* local_mac, const uint8_t* universal_mac)
* @return constant string "master"
*/
const char* system_get_sdk_version(void) __attribute__ ((deprecated));
/** @endcond */
/**
* Get IDF version
@ -264,13 +294,11 @@ typedef enum {
CHIP_ESP32 = 1, //!< ESP32
} esp_chip_model_t;
/**
* Chip feature flags, used in esp_chip_info_t
*/
#define CHIP_FEATURE_EMB_FLASH BIT(0)
#define CHIP_FEATURE_WIFI_BGN BIT(1)
#define CHIP_FEATURE_BLE BIT(4)
#define CHIP_FEATURE_BT BIT(5)
/* Chip feature flags, used in esp_chip_info_t */
#define CHIP_FEATURE_EMB_FLASH BIT(0) //!< Chip has embedded flash memory
#define CHIP_FEATURE_WIFI_BGN BIT(1) //!< Chip has 2.4GHz WiFi
#define CHIP_FEATURE_BLE BIT(4) //!< Chip has Bluetooth LE
#define CHIP_FEATURE_BT BIT(5) //!< Chip has Bluetooth Classic
/**
* @brief The structure represents information about the chip

View 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

View file

@ -32,6 +32,7 @@ SECTIONS
_rtc_bss_start = ABSOLUTE(.);
*rtc_wake_stub*.o(.bss .bss.*)
*rtc_wake_stub*.o(COMMON)
*(.rtc.bss)
_rtc_bss_end = ABSOLUTE(.);
} > rtc_slow_seg

View 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);
}

View file

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

View 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";

View 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();
}

View file

@ -0,0 +1,27 @@
#include "unity.h"
#include "esp_attr.h"
#include "esp_log.h"
static __NOINIT_ATTR uint32_t s_noinit;
static RTC_NOINIT_ATTR uint32_t s_rtc_noinit;
static RTC_DATA_ATTR uint32_t s_rtc_data;
extern int _rtc_noinit_start;
extern int _rtc_noinit_end;
extern int _rtc_data_start;
extern int _rtc_data_end;
extern int _noinit_start;
extern int _noinit_end;
static bool data_in_segment(void *ptr, int *seg_start, int *seg_end)
{
return ((intptr_t)ptr < (intptr_t)seg_end) && \
((intptr_t)ptr >= (intptr_t)seg_start);
}
TEST_CASE("Attributes place variables into correct sections", "[ld]")
{
TEST_ASSERT(data_in_segment(&s_noinit, &_noinit_start, &_noinit_end));
TEST_ASSERT(data_in_segment(&s_rtc_noinit, &_rtc_noinit_start, &_rtc_noinit_end));
TEST_ASSERT(data_in_segment(&s_rtc_data, &_rtc_data_start, &_rtc_data_end));
}

View file

@ -1,9 +0,0 @@
#include "unity.h"
#include "esp_system.h"
#include "string.h"
TEST_CASE("make exception", "[restart][reset=StoreProhibited,SW_CPU_RESET]")
{
*(int *) NULL = 0;
}

View file

@ -1,20 +0,0 @@
/*
Tests for the interrupt watchdog
*/
#include <esp_types.h>
#include <stdio.h>
#include "rom/ets_sys.h"
#include "unity.h"
#include "soc/dport_reg.h"
#include "soc/io_mux_reg.h"
#include "esp_intr_alloc.h"
#include "freertos/FreeRTOS.h"
TEST_CASE("Int wdt test", "[esp32][reset=Interrupt wdt timeout on CPU0,SW_CPU_RESET]")
{
portENTER_CRITICAL_NESTED();
while(1);
}

View file

@ -1,123 +0,0 @@
#include "unity.h"
#include "esp_system.h"
#include "rom/rtc.h"
#include "esp_log.h"
// This is a test sequence to test behavior of .rtc_noinit and .noinit sections.
// The values placed into .rtc_noinit section go to RTC SLOW Memory segment and
// keep their value after reset and deep sleep. Use new added attribute macro
// RTC_NOINIT_ATTR for this behavior. The second macro - __NOINIT_ATTR places value
// into .noinit section which goes to SRAM and will not be initialized after reset.
#define RTC_NOINIT_PATTERN 0xAAAAAAAA
#define _NOINIT_PATTERN 0x55555555
static __NOINIT_ATTR uint32_t noinit_data;
static RTC_NOINIT_ATTR uint32_t rtc_noinit_data;
extern int _rtc_noinit_start;
extern int _rtc_noinit_end;
extern int _noinit_start;
extern int _noinit_end;
// Pointers to the values
uint32_t *noinit_val_addr = (uint32_t*)&noinit_data;
uint32_t *rtc_noinit_val_addr = (uint32_t*)&rtc_noinit_data;
static const char* tag = "noinit_UnitTestMain";
static esp_err_t check_data_seg(uint32_t *value_address, \
uint32_t *seg_start, uint32_t *seg_end)
{
esp_err_t result = ESP_FAIL;
if (((uint32_t)value_address <= (uint32_t)seg_end) && \
((uint32_t)value_address >= (uint32_t)seg_start)){
result = ESP_OK;
}
return result;
}
static void setup_attributes(void)
{
rtc_noinit_data = RTC_NOINIT_PATTERN;
noinit_data = _NOINIT_PATTERN;
}
static void init_attributes(void)
{
setup_attributes();
printf("noinit_data = 0x%X \n", (uint32_t)*noinit_val_addr);
printf("rtc_noinit_data = 0x%X \n", (uint32_t)*rtc_noinit_val_addr);
TEST_ASSERT(*noinit_val_addr == noinit_data);
TEST_ASSERT(*rtc_noinit_val_addr == rtc_noinit_data);
}
static void reset_reason_power_on(void)
{
printf("This test case checks behavior of noinit variables POWERON_RESET sequence. \n");
RESET_REASON reason = rtc_get_reset_reason(0);
ESP_LOGI(tag, "POWERON_RESET reset values = (0x%X), (0x%X), reset reason=(%d)\n", \
(uint32_t)*noinit_val_addr, (uint32_t)*rtc_noinit_val_addr, (uint16_t)reason);
TEST_ASSERT((reason == POWERON_RESET) || (reason == RTCWDT_RTC_RESET));
init_attributes();
TEST_ASSERT(check_data_seg(noinit_val_addr, \
(uint32_t*)&_noinit_start, \
(uint32_t*)&_noinit_end) == ESP_OK);
TEST_ASSERT(check_data_seg(rtc_noinit_val_addr, \
(uint32_t*)&_rtc_noinit_start, \
(uint32_t*)&_rtc_noinit_end) == ESP_OK);
TEST_ASSERT(_NOINIT_PATTERN == *noinit_val_addr);
TEST_ASSERT(RTC_NOINIT_PATTERN == *rtc_noinit_val_addr);
printf("Next test case will check SOFTWARE_RESET behavior. \n");
esp_restart();
}
static void reset_reason_sw_reset(void)
{
printf("This test case checks behavior of noinit variables after software reset sequence. \n");
RESET_REASON reason = rtc_get_reset_reason(0);
ESP_LOGI(tag, "SW_CPU_RESET reset values = (0x%X), (0x%X), reset reason=(%d)\n", \
(uint32_t)*noinit_val_addr, (uint32_t)*rtc_noinit_val_addr, (uint16_t)reason);
TEST_ASSERT(reason == SW_CPU_RESET);
TEST_ASSERT(check_data_seg(noinit_val_addr, \
(uint32_t*)&_noinit_start, \
(uint32_t*)&_noinit_end) == ESP_OK);
TEST_ASSERT(check_data_seg(rtc_noinit_val_addr, \
(uint32_t*)&_rtc_noinit_start, \
(uint32_t*)&_rtc_noinit_end) == ESP_OK);
// The ROM bootloader behavior may apply to this assert.
// TEST_ASSERT(0x55555555 == *noinit_val_addr);
TEST_ASSERT(RTC_NOINIT_PATTERN == *rtc_noinit_val_addr);
printf("Go to deep sleep to check DEEP_SLEEP_RESET behavior. \n");
esp_sleep_enable_timer_wakeup(2000000);
esp_deep_sleep_start();
}
static void reset_reason_deep_sleep(void)
{
printf("This test case checks behavior of noinit variables after deep sleep reset. \n");
RESET_REASON reason = rtc_get_reset_reason(0);
ESP_LOGI(tag, "DEEP_SLEEP_RESET reset values = (0x%X), (0x%X), reset reason=(%d)\n", \
(uint32_t)*noinit_val_addr, (uint32_t)*rtc_noinit_val_addr, (uint16_t)reason);
TEST_ASSERT(reason == DEEPSLEEP_RESET);
TEST_ASSERT(check_data_seg(noinit_val_addr, \
(uint32_t*)&_noinit_start, \
(uint32_t*)&_noinit_end) == ESP_OK);
TEST_ASSERT(check_data_seg(rtc_noinit_val_addr, \
(uint32_t*)&_rtc_noinit_start, \
(uint32_t*)&_rtc_noinit_end) == ESP_OK);
TEST_ASSERT(RTC_NOINIT_PATTERN == *rtc_noinit_val_addr);
printf("The noinit test cases are done.. \n");
}
// The lines below are required to suppress GCC warnings about casting of function pointers
// in unity macro expansion. These warnings may be treated as errors during automated test.
#pragma GCC diagnostic push // required for GCC
#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
// The multiple stages test case to check values after certain reset reason
TEST_CASE_MULTIPLE_STAGES("NOINIT attributes behavior",
"[restart][reset=SW_CPU_RESET, DEEPSLEEP_RESET]",
reset_reason_power_on, reset_reason_sw_reset, reset_reason_deep_sleep);
#pragma GCC diagnostic pop // require GCC

View file

@ -0,0 +1,211 @@
#include "unity.h"
#include "esp_system.h"
#include "esp_task_wdt.h"
#include "esp_attr.h"
#include "soc/rtc_cntl_reg.h"
#define RTC_BSS_ATTR __attribute__((section(".rtc.bss")))
static __NOINIT_ATTR uint32_t s_noinit_val;
static RTC_NOINIT_ATTR uint32_t s_rtc_noinit_val;
static RTC_DATA_ATTR uint32_t s_rtc_data_val;
static RTC_BSS_ATTR uint32_t s_rtc_bss_val;
#define CHECK_VALUE 0x89abcdef
static void setup_values()
{
s_noinit_val = CHECK_VALUE;
s_rtc_noinit_val = CHECK_VALUE;
s_rtc_data_val = CHECK_VALUE;
s_rtc_bss_val = CHECK_VALUE;
}
/* This test needs special test runners: rev1 silicon, and SPI flash with
* fast start-up time. Otherwise reset reason will be RTCWDT_RESET.
*/
TEST_CASE("reset reason ESP_RST_POWERON", "[reset][ignore]")
{
TEST_ASSERT_EQUAL(ESP_RST_POWERON, esp_reset_reason());
}
static void do_deep_sleep()
{
setup_values();
esp_sleep_enable_timer_wakeup(10000);
esp_deep_sleep_start();
}
static void check_reset_reason_deep_sleep()
{
TEST_ASSERT_EQUAL(ESP_RST_DEEPSLEEP, esp_reset_reason());
TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_noinit_val);
TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_data_val);
TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_bss_val);
}
TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_DEEPSLEEP", "[reset_reason][reset=DEEPSLEEP_RESET]",
do_deep_sleep,
check_reset_reason_deep_sleep);
static void do_exception()
{
setup_values();
*(int*) (0x40000001) = 0;
}
static void do_abort()
{
setup_values();
abort();
}
static void check_reset_reason_panic()
{
TEST_ASSERT_EQUAL(ESP_RST_PANIC, esp_reset_reason());
TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_noinit_val);
TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_noinit_val);
TEST_ASSERT_EQUAL_HEX32(0, s_rtc_data_val);
TEST_ASSERT_EQUAL_HEX32(0, s_rtc_bss_val);
}
TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_PANIC after exception", "[reset_reason][reset=LoadStoreError,SW_CPU_RESET]",
do_exception,
check_reset_reason_panic);
TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_PANIC after abort", "[reset_reason][reset=abort,SW_CPU_RESET]",
do_abort,
check_reset_reason_panic);
static void do_restart()
{
setup_values();
esp_restart();
}
#if portNUM_PROCESSORS > 1
static void do_restart_from_app_cpu()
{
setup_values();
xTaskCreatePinnedToCore((TaskFunction_t) &do_restart, "restart", 2048, NULL, 5, NULL, 1);
vTaskDelay(2);
}
#endif
static void check_reset_reason_sw()
{
TEST_ASSERT_EQUAL(ESP_RST_SW, esp_reset_reason());
TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_noinit_val);
TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_noinit_val);
TEST_ASSERT_EQUAL_HEX32(0, s_rtc_data_val);
TEST_ASSERT_EQUAL_HEX32(0, s_rtc_bss_val);
}
TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_SW after restart", "[reset_reason][reset=SW_CPU_RESET]",
do_restart,
check_reset_reason_sw);
#if portNUM_PROCESSORS > 1
TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_SW after restart from APP CPU", "[reset_reason][reset=SW_CPU_RESET]",
do_restart_from_app_cpu,
check_reset_reason_sw);
#endif
static void do_int_wdt()
{
portENTER_CRITICAL_NESTED();
while(1);
}
static void do_int_wdt_hw()
{
XTOS_SET_INTLEVEL(XCHAL_NMILEVEL);
while(1);
}
static void check_reset_reason_int_wdt()
{
TEST_ASSERT_EQUAL(ESP_RST_INT_WDT, esp_reset_reason());
}
TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_INT_WDT after interrupt watchdog (panic)",
"[reset_reason][reset=Interrupt wdt timeout on CPU0,SW_CPU_RESET]",
do_int_wdt,
check_reset_reason_int_wdt);
TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_INT_WDT after interrupt watchdog (hw)",
"[reset_reason][reset=TG1WDT_SYS_RESET]",
do_int_wdt_hw,
check_reset_reason_int_wdt);
static void do_task_wdt()
{
setup_values();
esp_task_wdt_init(1, true);
esp_task_wdt_add(xTaskGetIdleTaskHandleForCPU(0));
while(1);
}
static void check_reset_reason_task_wdt()
{
TEST_ASSERT_EQUAL(ESP_RST_TASK_WDT, esp_reset_reason());
TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_noinit_val);
TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_noinit_val);
TEST_ASSERT_EQUAL_HEX32(0, s_rtc_data_val);
TEST_ASSERT_EQUAL_HEX32(0, s_rtc_bss_val);
}
TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_TASK_WDT after task watchdog",
"[reset_reason][reset=abort,SW_CPU_RESET]",
do_task_wdt,
check_reset_reason_task_wdt);
static void do_rtc_wdt()
{
WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE);
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_SYS_RESET_LENGTH, 7);
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, RTC_WDT_STG_SEL_RESET_SYSTEM);
WRITE_PERI_REG(RTC_CNTL_WDTCONFIG1_REG, 10000);
REG_SET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN);
while(1);
}
static void check_reset_reason_any_wdt()
{
TEST_ASSERT_EQUAL(ESP_RST_WDT, esp_reset_reason());
}
TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_WDT after RTC watchdog",
"[reset_reason][reset=RTCWDT_RTC_RESET]",
do_rtc_wdt,
check_reset_reason_any_wdt);
static void do_brownout()
{
setup_values();
printf("Manual test: lower the supply voltage to cause brownout\n");
vTaskSuspend(NULL);
}
static void check_reset_reason_brownout()
{
TEST_ASSERT_EQUAL(ESP_RST_BROWNOUT, esp_reset_reason());
TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_noinit_val);
TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_noinit_val);
TEST_ASSERT_EQUAL_HEX32(0, s_rtc_data_val);
TEST_ASSERT_EQUAL_HEX32(0, s_rtc_bss_val);
}
TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_BROWNOUT after brownout event",
"[reset_reason][ignore][reset=SW_CPU_RESET]",
do_brownout,
check_reset_reason_brownout);
/* Not tested here: ESP_RST_SDIO */

View file

@ -1,25 +0,0 @@
#include "unity.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
TEST_CASE("restart from PRO CPU", "[restart][reset=SW_CPU_RESET]")
{
esp_restart();
}
static void restart_task(void *arg)
{
esp_restart();
}
#ifndef CONFIG_FREERTOS_UNICORE
TEST_CASE("restart from APP CPU", "[restart][reset=SW_CPU_RESET]")
{
xTaskCreatePinnedToCore(&restart_task, "restart", 2048, NULL, 5, NULL, 1);
while (true) {
;
}
}
#endif

View file

@ -180,7 +180,9 @@ INPUT = \
../../components/freertos/include/freertos/event_groups.h \
../../components/freertos/include/freertos/ringbuf.h \
### Helper functions for error codes
../../components/esp32/include/esp_err.h
../../components/esp32/include/esp_err.h \
### System APIs
../../components/esp32/include/esp_system.h

View file

@ -1,82 +0,0 @@
Base MAC address
================
Overview
--------
Serveral MAC addresses (universally administered by IEEE) are uniquely assigned to the networking interfaces (WiFi/BT/Ethernet).
The final octet of each universally administered MAC address increases by one. Only the first one which is called base MAC address
of them is stored in EFUSE or external storage, the others are generated from it. Here, 'generate' means adding 0, 1, 2 and 3
(respectively) to the final octet of the base MAC address.
If the universally administered MAC addresses are not enough for all of the networking interfaces. Local administered MAC addresses
which are derived from universally administered MAC addresses are assigned to the reset of networking interfaces.
A `definition of local vs universal MAC address can be found on Wikipedia <https://en.wikipedia.org/wiki/MAC_address#Universal_vs._local>`_.
The number of universally administered MAC address can be configured using ``make menuconfig``.
Base MAC address
^^^^^^^^^^^^^^^^
If using the default base MAC address factory programmed by Espressif in BLK0 of EFUSE, nothing needs to be done.
If using a custom base MAC address stored in BLK3 of EFUSE, call API ``esp_efuse_mac_get_custom()`` to get the base MAC address
which is stored in BLK3 of EFUSE. If correct MAC address is returned, then call ``esp_base_mac_addr_set()`` to set the base MAC
address for system to generate the MAC addresses used by the networking interfaces(WiFi/BT/Ethernet).
There are 192 bits storage spaces for custom to store base MAC address in BLK3 of EFUSE. They are EFUSE_BLK3_RDATA0,
EFUSE_BLK3_RDATA1, EFUSE_BLK3_RDATA2, EFUSE_BLK3_RDATA3, EFUSE_BLK3_RDATA4 and EFUSE_BLK3_RDATA5, each of them is 32 bits
register. The format of the 192 bits storage spaces is:
.. highlight:: none
::
------------------------------------------------------
Field |Bits |Range |Description
------------------------------------------------------
version |8 |[191:184] |1: useful. 0: useless
------------------------------------------------------
reserve |112 |[183:72] |reserved
------------------------------------------------------
mac address |64 |[71:8] |base MAC address
------------------------------------------------------
mac crc |8 |[7:0] |crc of base MAC address
------------------------------------------------------
If using base MAC address stored in external storage, firstly get the base MAC address stored in external storage, then call
API ``esp_base_mac_addr_set()`` to set the base MAC address for system to generate the MAC addresses used by the networking
interfaces(WiFi/BT/Ethernet).
All of the steps must be done before initializing the networking interfaces(WiFi/BT/Ethernet). It is recommended to do it in
``app_main()`` which can be referenced in :example:`system/base_mac_address`.
Number of universally administered MAC address
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If the number of universal MAC addresses is two, only two interfaces (WiFi station and Bluetooth) receive a universally
administered MAC address. These are generated sequentially by adding 0 and 1 (respectively) to the base MAC address.
The remaining two interfaces (WiFi softap and Ethernet) receive local MAC addresses. These are derived from the universal
WiFi station and Bluetooth MAC addresses, respectively.
If the number of universal MAC addresses is four, all four interfaces (WiFi station, WiFi softap, Bluetooth and Ethernet)
receive a universally administered MAC address. These are generated sequentially by adding 0, 1, 2 and 3 (respectively)
to the final octet of the base MAC address.
When using the default (Espressif-assigned) base MAC address, either setting can be used. When using a custom universal MAC
address range, the correct setting will depend on the allocation of MAC addresses in this range (either 2 or 4 per device.)
API Reference
-------------
Header Files
^^^^^^^^^^^^
* :component_file:`esp32/include/esp_system.h`
Functions
---------
.. doxygenfunction:: esp_base_mac_addr_set
.. doxygenfunction:: esp_efuse_mac_get_custom

View file

@ -16,11 +16,11 @@ System API
Application Level Tracing <app_trace>
Power Management <power_management>
Sleep Modes <sleep_modes>
Base MAC address <base_mac_address>
Over The Air Updates (OTA) <ota>
ESP HTTPS OTA <esp_https_ota>
ESP pthread <esp_pthread>
Error Codes and Helper Functions <esp_err>
Miscellaneous System APIs <system>
Example code for this API section is provided in :example:`system` directory of ESP-IDF examples.

View file

@ -0,0 +1,118 @@
Miscellaneous System APIs
=========================
Software reset
--------------
To perform software reset of the chip, :cpp:func:`esp_restart` function is provided. When the function is called, execution of the program will stop, both CPUs will be reset, application will be loaded by the bootloader and started again.
Additionally, :cpp:func:`esp_register_shutdown_handler` function is provided to register a routine which needs to be called prior to restart (when done by :cpp:func:`esp_restart`). This is similar to the functionality of ``atexit`` POSIX function.
Reset reason
------------
ESP-IDF application can be started or restarted due to a variety of reasons. To get the last reset reason, call :cpp:func:`esp_reset_reason` function. See description of :cpp:type:`esp_reset_reason_t` for the list of possible reset reasons.
Heap memory
-----------
Two heap memory related functions are provided:
* :cpp:func:`esp_get_free_heap_size` returns the current size of free heap memory
* :cpp:func:`esp_get_minimum_free_heap_size` returns the minimum size of free heap memory that was available during program execution.
Note that ESP-IDF supports multiple heaps with different capabilities. Functions mentioned in this section return the size of heap memory which can be allocated using ``malloc`` family of functions. For further information about heap memory see :doc:`Heap Memory Allocation <mem_alloc>`.
Random number generation
------------------------
ESP32 contains a hardware random number generator, values from it can be obtained using :cpp:func:`esp_random`.
When Wi-Fi or Bluetooth are enabled, numbers returned by hardware random number generator (RNG) can be considered true random numbers. Without Wi-Fi or Bluetooth enabled, hardware RNG is a pseudo-random number generator. At startup, ESP-IDF bootloader seeds the hardware RNG with entropy, but care must be taken when reading random values between the start of ``app_main`` and initialization of Wi-Fi or Bluetooth drivers.
MAC Address
-----------
These APIs allow querying and customizing MAC addresses used by Wi-Fi, Bluetooth, and Ethernet drivers.
ESP32 has up to 4 network interfaces: Wi-Fi station, Wi-Fi AP, Ethernet, and Bluetooth. Each of these interfaces needs to have a MAC address assigned to it. In ESP-IDF these addresses are calculated from *Base MAC address*. Base MAC address can be initialized with factory-programmed value from EFUSE, or with a user-defined value. In addition to setting the base MAC address, applications can specify the way in which MAC addresses are allocated to devices. See `Number of universally administered MAC address`_ section for more details.
+---------------+--------------------------------+----------------------------------+
| Interface | MAC address | MAC address |
| | (4 universally administered) | (2 universally administered) |
+===============+================================+==================================+
| Wi-Fi Station | base_mac | base_mac |
+---------------+--------------------------------+----------------------------------+
| Wi-Fi SoftAP | base_mac, +1 to the last octet | base_mac, first octet randomized |
+---------------+--------------------------------+----------------------------------+
| Bluetooth | base_mac, +2 to the last octet | base_mac, +1 to the last octet |
+---------------+--------------------------------+----------------------------------+
| Ethernet | base_mac, +3 to the last octet | base_mac, +1 to the last octet, |
| | | first octet randomized |
+---------------+--------------------------------+----------------------------------+
Base MAC address
^^^^^^^^^^^^^^^^
Wi-Fi, Bluetooth, and Ethernet drivers use :cpp:func:`esp_read_mac` function to get MAC address for a specific interface.
By default, this function will use MAC address factory programmed in BLK0 of EFUSE as the base MAC address. MAC addresses of each interface will be calculated according to the table above.
Applications which don't use MAC address factory programmed into BLK0 of EFUSE can modify base MAC address used by :cpp:func:`esp_read_mac` using a call to :cpp:func:`esp_base_mac_addr_set`. Custom value of MAC address can come from application defined storage, such as Flash, NVS, etc. Note that the call to :cpp:func:`esp_base_mac_addr_set` needs to happen before network protocol stacks are initialized, for example, early in ``app_main``.
Custom MAC address in BLK3 of EFUSE
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To facilitate usage of custom MAC addresses, ESP-IDF provides :cpp:func:`esp_efuse_mac_get_custom` function, which loads MAC address from BLK3 of EFUSE. This function assumes that custom MAC address is stored in BLK3 of EFUSE (EFUSE_BLK3_RDATA0, EFUSE_BLK3_RDATA1, EFUSE_BLK3_RDATA2, EFUSE_BLK3_RDATA3, EFUSE_BLK3_RDATA4, EFUSE_BLK3_RDATA5 registers) in the following format:
+-----------------+-----------+---------------+------------------------------+
| Field | # of bits | Range of bits | Notes |
+=================+===========+===============+==============================+
| Version | 8 | 191:184 | 0: invalid, others — valid |
+-----------------+-----------+---------------+------------------------------+
| Reserved | 128 | 183:56 | |
+-----------------+-----------+---------------+------------------------------+
| MAC address | 48 | 55:8 | |
+-----------------+-----------+---------------+------------------------------+
| MAC address CRC | 8 | 7:0 | CRC-8-CCITT, polynomial 0x07 |
+-----------------+-----------+---------------+------------------------------+
Once MAC address has been obtained using :cpp:func:`esp_efuse_mac_get_custom`, call :cpp:func:`esp_base_mac_addr_set` to set this MAC address as base MAC address.
Number of universally administered MAC address
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Serveral MAC addresses (universally administered by IEEE) are uniquely assigned to the networking interfaces (Wi-Fi/BT/Ethernet). The final octet of each universally administered MAC address increases by one. Only the first one of them (which is called base MAC address) is stored in EFUSE or external storage, the others are generated from it. Here, 'generate' means adding 0, 1, 2 and 3 (respectively) to the final octet of the base MAC address.
If the universally administered MAC addresses are not enough for all of the networking interfaces, locally administered MAC addresses which are derived from universally administered MAC addresses are assigned to the rest of networking interfaces.
See `this article <https://en.wikipedia.org/wiki/MAC_address#Universal_vs._local>`_ for the definition of local and universally administered MAC addresses.
The number of universally administered MAC address can be configured using :envvar:`CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS`.
If the number of universal MAC addresses is two, only two interfaces (Wi-Fi Station and Bluetooth) receive a universally administered MAC address. These are generated sequentially by adding 0 and 1 (respectively) to the base MAC address. The remaining two interfaces (Wi-Fi SoftAP and Ethernet) receive local MAC addresses. These are derived from the universal Wi-Fi station and Bluetooth MAC addresses, respectively.
If the number of universal MAC addresses is four, all four interfaces (Wi-Fi Station, Wi-Fi SoftAP, Bluetooth and Ethernet) receive a universally administered MAC address. These are generated sequentially by adding 0, 1, 2 and 3 (respectively) to the final octet of the base MAC address.
When using the default (Espressif-assigned) base MAC address, either setting can be used. When using a custom universal MAC address range, the correct setting will depend on the allocation of MAC addresses in this range (either 2 or 4 per device.)
Chip version
------------
:cpp:func:`esp_chip_info` function fills :cpp:class:`esp_chip_info_t` structure with information about the chip. This includes the chip revision, number of CPU cores, and a bit mask of features enabled in the chip.
SDK version
-----------
:cpp:func:`esp_get_idf_version` returns a string describing the IDF version which was used to compile the application. This is the same value as the one available through ``IDF_VER`` variable of the build system. The version string generally has the format of ``git describe`` output.
API Reference
-------------
.. include:: /_build/inc/esp_system.inc

View file

@ -1 +0,0 @@
.. include:: ../../../en/api-reference/system/base_mac_address.rst

View file

@ -0,0 +1 @@
.. include:: ../../../en/api-reference/system/system.rst

View file

@ -576,7 +576,10 @@ class BaseDUT(object):
data = self.data_cache.get_data(time_remaining)
if match_succeed:
# do callback and flush matched data cache
# sort matched items according to order of appearance in the input data,
# so that the callbacks are invoked in correct order
matched_expect_items = sorted(matched_expect_items, key=lambda it: it["index"])
# invoke callbacks and flush matched data cache
slice_index = -1
for expect_item in matched_expect_items:
# trigger callback

View file

@ -43,7 +43,7 @@ from IDF.IDFApp import UT
UT_APP_BOOT_UP_DONE = "Press ENTER to see the list of tests."
RESET_PATTERN = re.compile(r"(ets [\w]{3}\s+[\d]{1,2} [\d]{4} [\d]{2}:[\d]{2}:[\d]{2}[^()]*\([\w].*?\))")
EXCEPTION_PATTERN = re.compile(r"(Guru Meditation Error: Core\s+\d panic'ed \([\w].*?\))")
ABORT_PATTERN = re.compile(r"(abort\(\) was called at PC 0x[a-eA-E\d]{8} on core \d)")
ABORT_PATTERN = re.compile(r"(abort\(\) was called at PC 0x[a-fA-F\d]{8} on core \d)")
FINISH_PATTERN = re.compile(r"1 Tests (\d) Failures (\d) Ignored")
END_LIST_STR = r'\r?\nEnter test for running'
TEST_PATTERN = re.compile(r'\((\d+)\)\s+"([^"]+)" ([^\r]+)\r?\n(' + END_LIST_STR + r')?')