mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
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
This commit is contained in:
parent
5953bca376
commit
7c02bde904
@ -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
components/esp_system/test/test_task_wdt.c
Normal file
95
components/esp_system/test/test_task_wdt.c
Normal file
@ -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());
|
||||
}
|
@ -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
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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];
|
||||
|
||||
//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");
|
||||
}
|
||||
|
@ -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')
|
||||
|
Loading…
x
Reference in New Issue
Block a user