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