From: Ivan Grokhotkov Date: Sun, 29 Jul 2018 11:17:09 +0000 (+0300) Subject: esp32/test: add tests for reset reasons X-Git-Tag: v3.2-beta1~299^2~1 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3ef650cd4630ff17017cede82e23784c25951e67;p=esp-idf esp32/test: add tests for reset reasons --- diff --git a/components/esp32/ld/esp32.common.ld b/components/esp32/ld/esp32.common.ld index 21470e6f40..a582b75978 100644 --- a/components/esp32/ld/esp32.common.ld +++ b/components/esp32/ld/esp32.common.ld @@ -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 diff --git a/components/esp32/test/test_attr.c b/components/esp32/test/test_attr.c new file mode 100644 index 0000000000..d6560b3cc8 --- /dev/null +++ b/components/esp32/test/test_attr.c @@ -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)); +} diff --git a/components/esp32/test/test_exception.c b/components/esp32/test/test_exception.c deleted file mode 100644 index 4e5d6dec20..0000000000 --- a/components/esp32/test/test_exception.c +++ /dev/null @@ -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; -} diff --git a/components/esp32/test/test_int_wdt.c b/components/esp32/test/test_int_wdt.c deleted file mode 100644 index 9bfde9cdca..0000000000 --- a/components/esp32/test/test_int_wdt.c +++ /dev/null @@ -1,20 +0,0 @@ -/* - Tests for the interrupt watchdog -*/ - -#include -#include -#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); -} diff --git a/components/esp32/test/test_noinit.c b/components/esp32/test/test_noinit.c deleted file mode 100644 index bb1b429392..0000000000 --- a/components/esp32/test/test_noinit.c +++ /dev/null @@ -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 diff --git a/components/esp32/test/test_reset_reason.c b/components/esp32/test/test_reset_reason.c new file mode 100644 index 0000000000..8a1d9a3b26 --- /dev/null +++ b/components/esp32/test/test_reset_reason.c @@ -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 */ diff --git a/components/esp32/test/test_restart.c b/components/esp32/test/test_restart.c deleted file mode 100644 index 6ad334da09..0000000000 --- a/components/esp32/test/test_restart.c +++ /dev/null @@ -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