1 #include "unity.h"
2 #include "esp_system.h"
3 #include "esp_task_wdt.h"
4 #include "esp_attr.h"
5 #include "soc/rtc.h"
6 #include "hal/wdt_hal.h"
7 #include "esp_sleep.h"
8 #if CONFIG_IDF_TARGET_ARCH_RISCV
9 #include "riscv/riscv_interrupts.h"
10 #endif
11 
12 #define RTC_BSS_ATTR __attribute__((section(".rtc.bss")))
13 
14 #define CHECK_VALUE 0x89abcdef
15 
16 static __NOINIT_ATTR uint32_t s_noinit_val;
17 static RTC_NOINIT_ATTR uint32_t s_rtc_noinit_val;
18 static RTC_DATA_ATTR uint32_t s_rtc_data_val;
19 static RTC_BSS_ATTR uint32_t s_rtc_bss_val;
20 /* There is no practical difference between placing something into RTC_DATA and
21  * RTC_RODATA. This only checks a usage pattern where the variable has a non-zero
22  * initializer (should be initialized by the bootloader).
23  */
24 static RTC_RODATA_ATTR uint32_t s_rtc_rodata_val = CHECK_VALUE;
25 static RTC_FAST_ATTR uint32_t s_rtc_force_fast_val;
26 static RTC_SLOW_ATTR uint32_t s_rtc_force_slow_val;
27 
28 #if CONFIG_IDF_TARGET_ESP32
29 #define DEEPSLEEP           "DEEPSLEEP_RESET"
30 #define LOAD_STORE_ERROR    "LoadStoreError"
31 #define RESET               "SW_CPU_RESET"
32 #define INT_WDT_PANIC       "Interrupt wdt timeout on CPU0"
33 #define INT_WDT             "TG1WDT_SYS_RESET"
34 #define RTC_WDT             "RTCWDT_RTC_RESET"
35 #ifdef CONFIG_ESP32_REV_MIN_3
36 #define BROWNOUT            "RTCWDT_BROWN_OUT_RESET"
37 #else
38 #define BROWNOUT            "SW_CPU_RESET"
39 #endif // CONFIG_ESP32_REV_MIN_3
40 #define STORE_ERROR         "StoreProhibited"
41 
42 #elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
43 #define DEEPSLEEP           "DSLEEP"
44 #define LOAD_STORE_ERROR    "LoadStoreError"
45 #define RESET               "RTC_SW_CPU_RST"
46 #define INT_WDT_PANIC       "Interrupt wdt timeout on CPU0"
47 #define INT_WDT             "TG1WDT_SYS_RST"
48 #define RTC_WDT             "RTCWDT_RTC_RST"
49 #define BROWNOUT            "BROWN_OUT_RST"
50 #define STORE_ERROR         "StoreProhibited"
51 
52 #elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
53 #define DEEPSLEEP           "DSLEEP"
54 #define LOAD_STORE_ERROR    "Store access fault"
55 #define RESET               "RTC_SW_CPU_RST"
56 #define INT_WDT_PANIC       "Interrupt wdt timeout on CPU0"
57 #define INT_WDT             "TG1WDT_SYS_RST"
58 #define RTC_WDT             "RTCWDT_RTC_RST"
59 #define BROWNOUT            "BROWNOUT_RST"
60 #define STORE_ERROR         LOAD_STORE_ERROR
61 
62 #endif // CONFIG_IDF_TARGET_ESP32
63 
setup_values(void)64 static void setup_values(void)
65 {
66     s_noinit_val = CHECK_VALUE;
67     s_rtc_noinit_val = CHECK_VALUE;
68     s_rtc_data_val = CHECK_VALUE;
69     s_rtc_bss_val = CHECK_VALUE;
70     TEST_ASSERT_EQUAL_HEX32_MESSAGE(CHECK_VALUE, s_rtc_rodata_val,
71             "s_rtc_rodata_val should already be set up");
72     s_rtc_force_fast_val = CHECK_VALUE;
73     s_rtc_force_slow_val = CHECK_VALUE;
74 }
75 
76 /* This test needs special test runners: rev1 silicon, and SPI flash with
77  * fast start-up time. Otherwise reset reason will be RTCWDT_RESET.
78  */
79 TEST_CASE("reset reason ESP_RST_POWERON", "[reset][ignore]")
80 {
81     TEST_ASSERT_EQUAL(ESP_RST_POWERON, esp_reset_reason());
82 }
83 
84 #if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3)
do_deep_sleep(void)85 static void do_deep_sleep(void)
86 {
87     setup_values();
88     esp_sleep_enable_timer_wakeup(10000);
89     esp_deep_sleep_start();
90 }
91 
check_reset_reason_deep_sleep(void)92 static void check_reset_reason_deep_sleep(void)
93 {
94     TEST_ASSERT_EQUAL(ESP_RST_DEEPSLEEP, esp_reset_reason());
95 
96     TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_noinit_val);
97     TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_data_val);
98     TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_bss_val);
99     TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_rodata_val);
100     TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_force_fast_val);
101     TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_force_slow_val);
102 }
103 
104 TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_DEEPSLEEP", "[reset_reason][reset="DEEPSLEEP"]",
105         do_deep_sleep,
106         check_reset_reason_deep_sleep);
107 #endif // TEMPORARY_DISABLED_FOR_TARGETS
108 
do_exception(void)109 static void do_exception(void)
110 {
111     setup_values();
112     *(int*) (0x40000001) = 0;
113 }
114 
do_abort(void)115 static void do_abort(void)
116 {
117     setup_values();
118     abort();
119 }
120 
check_reset_reason_panic(void)121 static void check_reset_reason_panic(void)
122 {
123     TEST_ASSERT_EQUAL(ESP_RST_PANIC, esp_reset_reason());
124 
125     TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_noinit_val);
126     TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_noinit_val);
127     TEST_ASSERT_EQUAL_HEX32(0, s_rtc_data_val);
128     TEST_ASSERT_EQUAL_HEX32(0, s_rtc_bss_val);
129     TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_rodata_val);
130     TEST_ASSERT_EQUAL_HEX32(0, s_rtc_force_fast_val);
131     TEST_ASSERT_EQUAL_HEX32(0, s_rtc_force_slow_val);
132 }
133 
134 TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_PANIC after exception", "[reset_reason][reset="LOAD_STORE_ERROR","RESET"]",
135         do_exception,
136         check_reset_reason_panic);
137 
138 TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_PANIC after abort", "[reset_reason][reset=abort,"RESET"]",
139         do_abort,
140         check_reset_reason_panic);
141 
do_restart(void)142 static void do_restart(void)
143 {
144     setup_values();
145     esp_restart();
146 }
147 
148 #if portNUM_PROCESSORS > 1
do_restart_from_app_cpu(void)149 static void do_restart_from_app_cpu(void)
150 {
151     setup_values();
152     xTaskCreatePinnedToCore((TaskFunction_t) &do_restart, "restart", 2048, NULL, 5, NULL, 1);
153     vTaskDelay(2);
154 }
155 #endif
156 
check_reset_reason_sw(void)157 static void check_reset_reason_sw(void)
158 {
159     TEST_ASSERT_EQUAL(ESP_RST_SW, esp_reset_reason());
160 
161     TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_noinit_val);
162     TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_noinit_val);
163     TEST_ASSERT_EQUAL_HEX32(0, s_rtc_data_val);
164     TEST_ASSERT_EQUAL_HEX32(0, s_rtc_bss_val);
165     TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_rodata_val);
166     TEST_ASSERT_EQUAL_HEX32(0, s_rtc_force_fast_val);
167     TEST_ASSERT_EQUAL_HEX32(0, s_rtc_force_slow_val);
168 }
169 
170 TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_SW after restart", "[reset_reason][reset="RESET"]",
171         do_restart,
172         check_reset_reason_sw);
173 
174 #if portNUM_PROCESSORS > 1
175 TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_SW after restart from APP CPU", "[reset_reason][reset="RESET"]",
176         do_restart_from_app_cpu,
177         check_reset_reason_sw);
178 #endif
179 
180 
do_int_wdt(void)181 static void do_int_wdt(void)
182 {
183     setup_values();
184     BaseType_t prev_level = portSET_INTERRUPT_MASK_FROM_ISR();
185     (void) prev_level;
186     while(1);
187 }
188 
do_int_wdt_hw(void)189 static void do_int_wdt_hw(void)
190 {
191     setup_values();
192 #if CONFIG_IDF_TARGET_ARCH_RISCV
193     riscv_global_interrupts_disable();
194 #else
195     XTOS_SET_INTLEVEL(XCHAL_NMILEVEL);
196 #endif
197     while(1);
198 }
199 
check_reset_reason_int_wdt(void)200 static void check_reset_reason_int_wdt(void)
201 {
202     TEST_ASSERT_EQUAL(ESP_RST_INT_WDT, esp_reset_reason());
203     TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_noinit_val);
204 }
205 
206 TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_INT_WDT after interrupt watchdog (panic)",
207         "[reset_reason][reset="INT_WDT_PANIC","RESET"]",
208         do_int_wdt,
209         check_reset_reason_int_wdt);
210 
211 TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_INT_WDT after interrupt watchdog (hw)",
212         "[reset_reason][reset="INT_WDT"]",
213         do_int_wdt_hw,
214         check_reset_reason_int_wdt);
215 
do_task_wdt(void)216 static void do_task_wdt(void)
217 {
218     setup_values();
219     esp_task_wdt_init(1, true);
220     esp_task_wdt_add(xTaskGetIdleTaskHandleForCPU(0));
221     while(1);
222 }
223 
check_reset_reason_task_wdt(void)224 static void check_reset_reason_task_wdt(void)
225 {
226     TEST_ASSERT_EQUAL(ESP_RST_TASK_WDT, esp_reset_reason());
227 
228     TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_noinit_val);
229     TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_noinit_val);
230     TEST_ASSERT_EQUAL_HEX32(0, s_rtc_data_val);
231     TEST_ASSERT_EQUAL_HEX32(0, s_rtc_bss_val);
232     TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_rodata_val);
233     TEST_ASSERT_EQUAL_HEX32(0, s_rtc_force_fast_val);
234     TEST_ASSERT_EQUAL_HEX32(0, s_rtc_force_slow_val);
235 }
236 
237 TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_TASK_WDT after task watchdog",
238         "[reset_reason][reset=abort,"RESET"]",
239         do_task_wdt,
240         check_reset_reason_task_wdt);
241 
do_rtc_wdt(void)242 static void do_rtc_wdt(void)
243 {
244     setup_values();
245     // Enable RTC watchdog for 0.1 second
246     wdt_hal_context_t rtc_wdt_ctx;
247     wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false);
248     uint32_t stage_timeout_ticks = rtc_clk_slow_freq_get_hz() / 10;
249     wdt_hal_write_protect_disable(&rtc_wdt_ctx);
250     wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_SYSTEM);
251     wdt_hal_set_flashboot_en(&rtc_wdt_ctx, true);
252     wdt_hal_write_protect_enable(&rtc_wdt_ctx);
253     while(1);
254 }
255 
check_reset_reason_any_wdt(void)256 static void check_reset_reason_any_wdt(void)
257 {
258     TEST_ASSERT_EQUAL(ESP_RST_WDT, esp_reset_reason());
259     TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_noinit_val);
260 }
261 
262 TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_WDT after RTC watchdog",
263         "[reset_reason][reset="RTC_WDT"]",
264         do_rtc_wdt,
265         check_reset_reason_any_wdt);
266 
267 
do_brownout(void)268 static void do_brownout(void)
269 {
270     setup_values();
271     printf("Manual test: lower the supply voltage to cause brownout\n");
272     vTaskSuspend(NULL);
273 }
274 
check_reset_reason_brownout(void)275 static void check_reset_reason_brownout(void)
276 {
277     TEST_ASSERT_EQUAL(ESP_RST_BROWNOUT, esp_reset_reason());
278 
279     TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_noinit_val);
280     TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_noinit_val);
281     TEST_ASSERT_EQUAL_HEX32(0, s_rtc_data_val);
282     TEST_ASSERT_EQUAL_HEX32(0, s_rtc_bss_val);
283     TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_rodata_val);
284     TEST_ASSERT_EQUAL_HEX32(0, s_rtc_force_fast_val);
285     TEST_ASSERT_EQUAL_HEX32(0, s_rtc_force_slow_val);
286 }
287 
288 TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_BROWNOUT after brownout event",
289         "[reset_reason][ignore][reset="BROWNOUT"]",
290         do_brownout,
291         check_reset_reason_brownout);
292 
293 
294 #ifdef CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
295 #ifndef CONFIG_FREERTOS_UNICORE
296 #include "xt_instr_macros.h"
297 #include "xtensa/config/specreg.h"
298 
299 static int size_stack = 1024 * 3;
300 static StackType_t *start_addr_stack;
301 
fibonacci(int n,void * func (void))302 static int fibonacci(int n, void* func(void))
303 {
304     int tmp1 = n, tmp2 = n;
305     uint32_t base, start;
306     RSR(WINDOWBASE, base);
307     RSR(WINDOWSTART, start);
308     printf("WINDOWBASE = %-2d   WINDOWSTART = 0x%x\n", base, start);
309     if (n <= 1) {
310         StackType_t *last_addr_stack = esp_cpu_get_sp();
311         StackType_t *used_stack = (StackType_t *) (start_addr_stack - last_addr_stack);
312         printf("addr_stack = %p, used[%p]/all[0x%x] space in stack\n", last_addr_stack, used_stack, size_stack);
313         func();
314         return n;
315     }
316     int fib = fibonacci(n - 1, func) + fibonacci(n - 2, func);
317     printf("fib = %d\n", (tmp1 - tmp2) + fib);
318     return fib;
319 }
320 
test_task(void * func)321 static void test_task(void *func)
322 {
323     start_addr_stack = esp_cpu_get_sp();
324     if (esp_ptr_external_ram(start_addr_stack)) {
325         printf("restart_task: uses external stack, addr_stack = %p\n", start_addr_stack);
326     } else {
327         printf("restart_task: uses internal stack, addr_stack = %p\n", start_addr_stack);
328     }
329     fibonacci(35, func);
330 }
331 
func_do_exception(void)332 static void func_do_exception(void)
333 {
334     *((int *) 0) = 0;
335 }
336 
init_restart_task(void)337 static void init_restart_task(void)
338 {
339     StackType_t *stack_for_task = (StackType_t *) heap_caps_calloc(1, size_stack, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
340     printf("init_task: current addr_stack = %p, stack_for_task = %p\n", esp_cpu_get_sp(), stack_for_task);
341     static StaticTask_t task_buf;
342     xTaskCreateStaticPinnedToCore(test_task, "test_task", size_stack, esp_restart, 5, stack_for_task, &task_buf, 1);
343     while (1) { };
344 }
345 
init_task_do_exception(void)346 static void init_task_do_exception(void)
347 {
348     StackType_t *stack_for_task = (StackType_t *) heap_caps_calloc(1, size_stack, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
349     printf("init_task: current addr_stack = %p, stack_for_task = %p\n", esp_cpu_get_sp(), stack_for_task);
350     static StaticTask_t task_buf;
351     xTaskCreateStaticPinnedToCore(test_task, "test_task", size_stack, func_do_exception, 5, stack_for_task, &task_buf, 1);
352     while (1) { };
353 }
354 
test1_finish(void)355 static void test1_finish(void)
356 {
357     TEST_ASSERT_EQUAL(ESP_RST_SW, esp_reset_reason());
358     printf("test - OK\n");
359 }
360 
test2_finish(void)361 static void test2_finish(void)
362 {
363     TEST_ASSERT_EQUAL(ESP_RST_PANIC, esp_reset_reason());
364     printf("test - OK\n");
365 }
366 
367 TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_SW after restart in a task with spiram stack", "[spiram_stack][reset="RESET"]",
368         init_restart_task,
369         test1_finish);
370 
371 TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_PANIC after an exception in a task with spiram stack", "[spiram_stack][reset="STORE_ERROR","RESET"]",
372         init_task_do_exception,
373         test2_finish);
374 
375 #endif // CONFIG_FREERTOS_UNICORE
376 #endif // CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
377 
378 
379 /* Not tested here: ESP_RST_SDIO */
380