Quellcode durchsuchen

esp_system: Update task watchdog unit tests and example

This commit does the following:

- Update existing unit tests that use the TWDT to call the new
  esp_task_wdt_init() API
- Add a set of dedicate TWDT unit tests
- Updates the TWDT example
Darian Leung vor 3 Jahren
Ursprung
Commit
7c02bde904

+ 6 - 2
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);
 }
 

+ 95 - 0
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 <stdbool.h>
+#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());
+}

+ 7 - 5
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
 
 }

+ 25 - 20
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

+ 76 - 58
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 <stdio.h>
 #include <stdlib.h>
 #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];
+static void func_a(void)
+{
+    esp_task_wdt_reset_user(func_a_twdt_user_hdl);
+}
 
-//Callback for user tasks created in app_main()
-void reset_task(void *arg)
+static void func_b(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);
-
-    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));
-    }
+    esp_task_wdt_reset_user(func_b_twdt_user_hdl);
 }
 
-void app_main(void)
+void task_func(void *arg)
 {
-    printf("Initialize TWDT\n");
-    //Initialize or reinitialize TWDT
-    CHECK_ERROR_CODE(esp_task_wdt_init(TWDT_TIMEOUT_S, false), ESP_OK);
-
-    //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 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);
+    // 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));
     }
 
-    printf("Delay for 10 seconds\n");
-    vTaskDelay(pdMS_TO_TICKS(10000));   //Delay for 10 seconds
+    // 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("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
+    printf("Unsubscribed from TWDT\n");
 
-        //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
+    // Notify main task of deletion
+    xTaskNotifyGive((TaskHandle_t)arg);
+    vTaskDelete(NULL);
+}
 
-    printf("Complete\n");
+void app_main(void)
+{
+#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
+
+    // Create a task
+    run_loop = true;
+    xTaskCreatePinnedToCore(task_func, "task", 2048, xTaskGetCurrentTaskHandle(), 10, NULL, 0);
+
+    // 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));
+
+    // Stop the created task
+    run_loop = false;
+    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
+
+#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");
 }

+ 1 - 4
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')