diff --git a/components/esp_system/test/test_reset_reason.c b/components/esp_system/test/test_reset_reason.c index 83064e458f..af32cf6242 100644 --- a/components/esp_system/test/test_reset_reason.c +++ b/components/esp_system/test/test_reset_reason.c @@ -216,8 +216,12 @@ TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_INT_WDT after interrupt watchdog static void do_task_wdt(void) { setup_values(); - esp_task_wdt_init(1, true); - esp_task_wdt_add(xTaskGetIdleTaskHandleForCPU(0)); + esp_task_wdt_config_t twdt_config = { + .timeout_ms = 1000, + .idle_core_mask = (1 << 0), // Watch core 0 idle + .trigger_panic = true, + }; + TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_init(&twdt_config)); while(1); } diff --git a/components/esp_system/test/test_task_wdt.c b/components/esp_system/test/test_task_wdt.c new file mode 100644 index 0000000000..f726216071 --- /dev/null +++ b/components/esp_system/test/test_task_wdt.c @@ -0,0 +1,95 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include +#include "unity.h" +#include "esp_rom_sys.h" +#include "esp_task_wdt.h" + +#define TASK_WDT_TIMEOUT_MS 1000 + +static bool timeout_flag; + +void esp_task_wdt_isr_user_handler(void) +{ + timeout_flag = true; +} + +TEST_CASE("Task WDT task timeout", "[task_wdt]") +{ + timeout_flag = false; + esp_task_wdt_config_t twdt_config = { + .timeout_ms = TASK_WDT_TIMEOUT_MS, + .idle_core_mask = 0, + .trigger_panic = false, + }; + TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_init(&twdt_config)); + TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_add(NULL)); + // Short delay to allow timeout to occur + esp_rom_delay_us(TASK_WDT_TIMEOUT_MS * 1000); + TEST_ASSERT_EQUAL(true, timeout_flag); + TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_delete(NULL)); + TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_deinit()); +} + +TEST_CASE("Task WDT task feed", "[task_wdt]") +{ + timeout_flag = false; + esp_task_wdt_config_t twdt_config = { + .timeout_ms = TASK_WDT_TIMEOUT_MS, + .idle_core_mask = 0, + .trigger_panic = false, + }; + TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_init(&twdt_config)); + TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_add(NULL)); + // Feed the watchdog after a short delay + esp_rom_delay_us((TASK_WDT_TIMEOUT_MS * 1000) / 2); + TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_reset()); + esp_rom_delay_us((TASK_WDT_TIMEOUT_MS * 1000) / 2); + TEST_ASSERT_EQUAL(false, timeout_flag); + TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_delete(NULL)); + TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_deinit()); +} + +TEST_CASE("Task WDT user timeout", "[task_wdt]") +{ + const char *user_name = "test_user"; + esp_task_wdt_user_handle_t user_handle; + timeout_flag = false; + esp_task_wdt_config_t twdt_config = { + .timeout_ms = TASK_WDT_TIMEOUT_MS, + .idle_core_mask = 0, + .trigger_panic = false, + }; + TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_init(&twdt_config)); + TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_add_user(user_name, &user_handle)); + // Short delay to allow timeout to occur + esp_rom_delay_us(TASK_WDT_TIMEOUT_MS * 1000); + TEST_ASSERT_EQUAL(true, timeout_flag); + TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_delete_user(user_handle)); + TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_deinit()); +} + +TEST_CASE("Task WDT user feed", "[task_wdt]") +{ + const char *user_name = "test_user"; + esp_task_wdt_user_handle_t user_handle; + timeout_flag = false; + esp_task_wdt_config_t twdt_config = { + .timeout_ms = TASK_WDT_TIMEOUT_MS, + .idle_core_mask = 0, + .trigger_panic = false, + }; + TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_init(&twdt_config)); + TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_add_user(user_name, &user_handle)); + // Feed the watchdog after a short delay + esp_rom_delay_us((TASK_WDT_TIMEOUT_MS * 1000) / 2); + TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_reset_user(user_handle)); + esp_rom_delay_us((TASK_WDT_TIMEOUT_MS * 1000) / 2); + TEST_ASSERT_EQUAL(false, timeout_flag); + TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_delete_user(user_handle)); + TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_deinit()); +} diff --git a/components/mbedtls/test/test_rsa.c b/components/mbedtls/test/test_rsa.c index 52ce354948..e795a6d2de 100644 --- a/components/mbedtls/test/test_rsa.c +++ b/components/mbedtls/test/test_rsa.c @@ -545,9 +545,12 @@ TEST_CASE("mbedtls RSA Generate Key", "[mbedtls][timeout=60]") #if CONFIG_MBEDTLS_MPI_USE_INTERRUPT /* Check that generating keys doesnt starve the watchdog if interrupt-based driver is used */ - const int timeout_s = 1; - esp_task_wdt_init(timeout_s, true); - esp_task_wdt_add(xTaskGetIdleTaskHandleForCPU(0)); + esp_task_wdt_config_t twdt_config = { + .timeout_ms = 1000, + .idle_core_mask = (1 << 0), // Watch core 0 idle + .trigger_panic = true, + }; + TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_init(&twdt_config)); #endif //CONFIG_MBEDTLS_MPI_USE_INTERRUPT mbedtls_rsa_init(&ctx); @@ -563,8 +566,7 @@ TEST_CASE("mbedtls RSA Generate Key", "[mbedtls][timeout=60]") mbedtls_entropy_free(&entropy); #if CONFIG_MBEDTLS_MPI_USE_INTERRUPT - esp_task_wdt_delete(xTaskGetIdleTaskHandleForCPU(0)); - esp_task_wdt_deinit(); + TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_deinit()); #endif //CONFIG_MBEDTLS_MPI_USE_INTERRUPT } diff --git a/examples/system/task_watchdog/README.md b/examples/system/task_watchdog/README.md index fce2255db7..4340a9ea29 100644 --- a/examples/system/task_watchdog/README.md +++ b/examples/system/task_watchdog/README.md @@ -1,8 +1,11 @@ # Task Watchdog Example -This test code shows how to initialize the task watchdog, add tasks to the -watchdog task list, feeding the tasks, deleting tasks from the watchdog task -list, and deinitializing the task watchdog. +The following example demonstrates how to use the following features of the task watchdog timer (TWDT): + +- How to initialize and deinitialize the TWDT +- How to subscribe and unsubscribe tasks to the TWDT +- How to subscribe and unsubscribe users to the TWDT +- How to tasks and users can reset (i.e., feed) the TWDT ## How to use example @@ -15,7 +18,7 @@ Before project configuration and build, be sure to set the correct chip target u ### Configure the project -Program should run without error. Comment out `esp_task_wdt_reset()` to observe a watchdog timeout. +Program should run correctly without needing any special configuration. However, users can disable `CONFIG_ESP_TASK_WDT` which will prevent the TWDT from being automatically initialized on startup. If disabled, the example will manually initialize the TWDT. ### Build and Flash @@ -29,31 +32,33 @@ See the [ESP-IDF Getting Started Guide](https://idf.espressif.com/) for all the ## Example Output -As you run the example, you will see the following log: - -With `esp_task_wdt_reset()`: +When the example runs normally, the following output will be observed: ``` +I (316) cpu_start: Starting scheduler on PRO CPU. I (0) cpu_start: Starting scheduler on APP CPU. -Initialize TWDT +TWDT initialized +Subscribed to TWDT Delay for 10 seconds -Unsubscribing and deleting tasks -Complete +Unsubscribed from TWDT +TWDT deinitialized +Example complete ``` -Without `esp_task_wdt_reset()`: +Users can comment out any of the `esp_task_wdt_reset()` or `esp_task_wdt_reset_user()` calls to trigger the TWDT, which in turn will result in the following output: + ``` +I (316) cpu_start: Starting scheduler on PRO CPU. I (0) cpu_start: Starting scheduler on APP CPU. -Initialize TWDT +TWDT initialized +Subscribed to TWDT Delay for 10 seconds -E (6316) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time: -E (6316) task_wdt: - reset task (CPU 0) -E (6316) task_wdt: - reset task (CPU 1) -E (6316) task_wdt: Tasks currently running: -E (6316) task_wdt: CPU 0: IDLE -E (6316) task_wdt: CPU 1: IDLE -E (6316) task_wdt: Print CPU 0 (current core) backtrace - +E (6326) task_wdt: Task watchdog got triggered. The following tasks/users did not reset the watchdog in time: +E (6326) task_wdt: - task (CPU 0) +E (6326) task_wdt: Tasks currently running: +E (6326) task_wdt: CPU 0: IDLE +E (6326) task_wdt: CPU 1: IDLE +E (6326) task_wdt: Print CPU 0 (current core) backtrace ``` ## Troubleshooting diff --git a/examples/system/task_watchdog/main/task_watchdog_example_main.c b/examples/system/task_watchdog/main/task_watchdog_example_main.c index c1b25691b2..2ff643b2cb 100644 --- a/examples/system/task_watchdog/main/task_watchdog_example_main.c +++ b/examples/system/task_watchdog/main/task_watchdog_example_main.c @@ -6,80 +6,98 @@ software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ + +#include "sdkconfig.h" #include #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "esp_err.h" #include "esp_task_wdt.h" -#define TWDT_TIMEOUT_S 3 -#define TASK_RESET_PERIOD_S 2 +#define TWDT_TIMEOUT_MS 3000 +#define TASK_RESET_PERIOD_MS 2000 +#define MAIN_DELAY_MS 10000 -/* - * Macro to check the outputs of TWDT functions and trigger an abort if an - * incorrect code is returned. - */ -#define CHECK_ERROR_CODE(returned, expected) ({ \ - if(returned != expected){ \ - printf("TWDT ERROR\n"); \ - abort(); \ - } \ -}) +static volatile bool run_loop; +static esp_task_wdt_user_handle_t func_a_twdt_user_hdl; +static esp_task_wdt_user_handle_t func_b_twdt_user_hdl; -static TaskHandle_t task_handles[portNUM_PROCESSORS]; - -//Callback for user tasks created in app_main() -void reset_task(void *arg) +static void func_a(void) { - //Subscribe this task to TWDT, then check if it is subscribed - CHECK_ERROR_CODE(esp_task_wdt_add(NULL), ESP_OK); - CHECK_ERROR_CODE(esp_task_wdt_status(NULL), ESP_OK); + esp_task_wdt_reset_user(func_a_twdt_user_hdl); +} - while(1){ - //reset the watchdog every 2 seconds - CHECK_ERROR_CODE(esp_task_wdt_reset(), ESP_OK); //Comment this line to trigger a TWDT timeout - vTaskDelay(pdMS_TO_TICKS(TASK_RESET_PERIOD_S * 1000)); +static void func_b(void) +{ + esp_task_wdt_reset_user(func_b_twdt_user_hdl); +} + +void task_func(void *arg) +{ + // Subscribe this task to TWDT, then check if it is subscribed + ESP_ERROR_CHECK(esp_task_wdt_add(NULL)); + ESP_ERROR_CHECK(esp_task_wdt_status(NULL)); + + // Subscribe func_a and func_b as users of the the TWDT + ESP_ERROR_CHECK(esp_task_wdt_add_user("func_a", &func_a_twdt_user_hdl)); + ESP_ERROR_CHECK(esp_task_wdt_add_user("func_b", &func_b_twdt_user_hdl)); + + printf("Subscribed to TWDT\n"); + + while (run_loop) { + // Reset the task and each user periodically + /* + Note: Comment out any one of the calls below to trigger the TWDT + */ + esp_task_wdt_reset(); + func_a(); + func_b(); + + vTaskDelay(pdMS_TO_TICKS(TASK_RESET_PERIOD_MS)); } + + // Unsubscribe this task, func_a, and func_b + ESP_ERROR_CHECK(esp_task_wdt_delete_user(func_a_twdt_user_hdl)); + ESP_ERROR_CHECK(esp_task_wdt_delete_user(func_b_twdt_user_hdl)); + ESP_ERROR_CHECK(esp_task_wdt_delete(NULL)); + + printf("Unsubscribed from TWDT\n"); + + // Notify main task of deletion + xTaskNotifyGive((TaskHandle_t)arg); + vTaskDelete(NULL); } void app_main(void) { - printf("Initialize TWDT\n"); - //Initialize or reinitialize TWDT - CHECK_ERROR_CODE(esp_task_wdt_init(TWDT_TIMEOUT_S, false), ESP_OK); +#if !CONFIG_ESP_TASK_WDT + // If the TWDT was not initialized automatically on startup, manually intialize it now + esp_task_wdt_config_t twdt_config = { + .timeout_ms = TWDT_TIMEOUT_MS, + .idle_core_mask = (1 << portNUM_PROCESSORS) - 1, // Bitmask of all cores + .trigger_panic = false, + }; + ESP_ERROR_CHECK(esp_task_wdt_init(&twdt_config)); + printf("TWDT initialized\n"); +#endif // CONFIG_ESP_TASK_WDT - //Subscribe Idle Tasks to TWDT if they were not subscribed at startup -#ifndef CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 - esp_task_wdt_add(xTaskGetIdleTaskHandleForCPU(0)); -#endif -#if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1 && !CONFIG_FREERTOS_UNICORE - esp_task_wdt_add(xTaskGetIdleTaskHandleForCPU(1)); -#endif + // Create a task + run_loop = true; + xTaskCreatePinnedToCore(task_func, "task", 2048, xTaskGetCurrentTaskHandle(), 10, NULL, 0); - //Create user tasks and add them to watchdog - for(int i = 0; i < portNUM_PROCESSORS; i++){ - xTaskCreatePinnedToCore(reset_task, "reset task", 1024, NULL, 10, &task_handles[i], i); - } + // Let the created task run for a while + printf("Delay for %d seconds\n", MAIN_DELAY_MS/1000); + vTaskDelay(pdMS_TO_TICKS(MAIN_DELAY_MS)); - printf("Delay for 10 seconds\n"); - vTaskDelay(pdMS_TO_TICKS(10000)); //Delay for 10 seconds + // Stop the created task + run_loop = false; + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - printf("Unsubscribing and deleting tasks\n"); - //Delete and unsubscribe Users Tasks from Task Watchdog, then unsubscribe idle task - for(int i = 0; i < portNUM_PROCESSORS; i++){ - vTaskDelete(task_handles[i]); //Delete user task first (prevents the resetting of an unsubscribed task) - CHECK_ERROR_CODE(esp_task_wdt_delete(task_handles[i]), ESP_OK); //Unsubscribe task from TWDT - CHECK_ERROR_CODE(esp_task_wdt_status(task_handles[i]), ESP_ERR_NOT_FOUND); //Confirm task is unsubscribed - - //unsubscribe idle task - CHECK_ERROR_CODE(esp_task_wdt_delete(xTaskGetIdleTaskHandleForCPU(i)), ESP_OK); //Unsubscribe Idle Task from TWDT - CHECK_ERROR_CODE(esp_task_wdt_status(xTaskGetIdleTaskHandleForCPU(i)), ESP_ERR_NOT_FOUND); //Confirm Idle task has unsubscribed - } - - - //Deinit TWDT after all tasks have unsubscribed - CHECK_ERROR_CODE(esp_task_wdt_deinit(), ESP_OK); - CHECK_ERROR_CODE(esp_task_wdt_status(NULL), ESP_ERR_INVALID_STATE); //Confirm TWDT has been deinitialized - - printf("Complete\n"); +#if !CONFIG_ESP_TASK_WDT + // If we manually initialized the TWDT, deintialize it now + ESP_ERROR_CHECK(esp_task_wdt_deinit()); + printf("TWDT deinitialized\n"); +#endif // CONFIG_ESP_TASK_WDT + printf("Example complete\n"); } diff --git a/examples/system/task_watchdog/pytest_task_watchdog.py b/examples/system/task_watchdog/pytest_task_watchdog.py index ad88bae99e..7a4a8e223f 100644 --- a/examples/system/task_watchdog/pytest_task_watchdog.py +++ b/examples/system/task_watchdog/pytest_task_watchdog.py @@ -9,7 +9,4 @@ from pytest_embedded import Dut @pytest.mark.generic def test_task_watchdog(dut: Dut) -> None: - dut.expect_exact('Initialize TWDT') - dut.expect_exact('Delay for 10 seconds') - dut.expect_exact('Unsubscribing and deleting tasks') - dut.expect_exact('Complete') + dut.expect_exact('Example complete')