mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-06 06:04:33 +02:00
esp_system: Refactor task_wdt
This commit refactors the task watchdog as follows: - Renamed variables, types, and functions - Replaced manual linked list implementation with SLIST() - Moved calloc()/free() calls out of critical sections - Shortened ISR critical sections - Updated API description - Updated code formatting
This commit is contained in:
@@ -1,16 +1,8 @@
|
|||||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
/*
|
||||||
//
|
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
*
|
||||||
// you may not use this file except in compliance with the License.
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
// You may obtain a copy of the License at
|
*/
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
@@ -25,123 +17,96 @@ extern "C" {
|
|||||||
/**
|
/**
|
||||||
* @brief Initialize the Task Watchdog Timer (TWDT)
|
* @brief Initialize the Task Watchdog Timer (TWDT)
|
||||||
*
|
*
|
||||||
* This function configures and initializes the TWDT. If the TWDT is already
|
* This function configures and initializes the TWDT. If the TWDT is already initialized when this function is called,
|
||||||
* initialized when this function is called, this function will update the
|
* this function will update the TWDT's timeout period and panic configurations instead. After initializing the TWDT,
|
||||||
* TWDT's timeout period and panic configurations instead. After initializing
|
* any task can elect to be watched by the TWDT by subscribing to it using esp_task_wdt_add().
|
||||||
* the TWDT, any task can elect to be watched by the TWDT by subscribing to it
|
|
||||||
* using esp_task_wdt_add().
|
|
||||||
*
|
*
|
||||||
|
* @note esp_task_wdt_init() must only be called after the scheduler started
|
||||||
* @param[in] timeout Timeout period of TWDT in seconds
|
* @param[in] timeout Timeout period of TWDT in seconds
|
||||||
* @param[in] panic Flag that controls whether the panic handler will be
|
* @param[in] panic Flag that controls whether the panic handler will be executed when the TWDT times out
|
||||||
* executed when the TWDT times out
|
|
||||||
*
|
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: Initialization was successful
|
* - ESP_OK: Initialization was successful
|
||||||
* - ESP_ERR_NO_MEM: Initialization failed due to lack of memory
|
* - ESP_ERR_NO_MEM: Initialization failed due insufficient memory
|
||||||
*
|
|
||||||
* @note esp_task_wdt_init() must only be called after the scheduler
|
|
||||||
* started
|
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_task_wdt_init(uint32_t timeout, bool panic);
|
esp_err_t esp_task_wdt_init(uint32_t timeout, bool panic);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Deinitialize the Task Watchdog Timer (TWDT)
|
* @brief Deinitialize the Task Watchdog Timer (TWDT)
|
||||||
*
|
*
|
||||||
* This function will deinitialize the TWDT. Calling this function whilst tasks
|
* This function will deinitialize the TWDT. Calling this function whilst tasks are still subscribed to the TWDT, or
|
||||||
* are still subscribed to the TWDT, or when the TWDT is already deinitialized,
|
* when the TWDT is already deinitialized, will result in an error code being returned.
|
||||||
* will result in an error code being returned.
|
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: TWDT successfully deinitialized
|
* - ESP_OK: TWDT successfully deinitialized
|
||||||
* - ESP_ERR_INVALID_STATE: Error, tasks are still subscribed to the TWDT
|
* - ESP_ERR_INVALID_STATE: TWDT was never initialized, or tasks are still subscribed
|
||||||
* - ESP_ERR_NOT_FOUND: Error, TWDT has already been deinitialized
|
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_task_wdt_deinit(void);
|
esp_err_t esp_task_wdt_deinit(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Subscribe a task to the Task Watchdog Timer (TWDT)
|
* @brief Subscribe a task to the Task Watchdog Timer (TWDT)
|
||||||
*
|
*
|
||||||
* This function subscribes a task to the TWDT. Each subscribed task must
|
* This function subscribes a task to the TWDT. Each subscribed task must periodically call esp_task_wdt_reset() to
|
||||||
* periodically call esp_task_wdt_reset() to prevent the TWDT from elapsing its
|
* prevent the TWDT from elapsing its timeout period. Failure to do so will result in a TWDT timeout. If the task being
|
||||||
* timeout period. Failure to do so will result in a TWDT timeout. If the task
|
* subscribed is one of the Idle Tasks, this function will automatically enable esp_task_wdt_reset() to called from the
|
||||||
* being subscribed is one of the Idle Tasks, this function will automatically
|
* Idle Hook of the Idle Task.
|
||||||
* enable esp_task_wdt_reset() to called from the Idle Hook of the Idle Task.
|
|
||||||
* Calling this function whilst the TWDT is uninitialized or attempting to
|
|
||||||
* subscribe an already subscribed task will result in an error code being
|
|
||||||
* returned.
|
|
||||||
*
|
*
|
||||||
* @param[in] handle Handle of the task. Input NULL to subscribe the current
|
* Calling this function whilst the TWDT is uninitialized or attempting to subscribe an already subscribed task will
|
||||||
* running task to the TWDT
|
* result in an error code being returned.
|
||||||
*
|
*
|
||||||
|
* @param handle Handle of the task. Input NULL to subscribe the current running task to the TWDT
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: Successfully subscribed the task to the TWDT
|
* - ESP_OK: Successfully subscribed the task to the TWDT
|
||||||
* - ESP_ERR_INVALID_ARG: Error, the task is already subscribed
|
* - ESP_ERR_INVALID_ARG: The task is already subscribed
|
||||||
* - ESP_ERR_NO_MEM: Error, could not subscribe the task due to lack of
|
* - ESP_ERR_NO_MEM: Could not subscribe the insufficient memory
|
||||||
* memory
|
* - ESP_ERR_INVALID_STATE: TWDT was never initialized
|
||||||
* - ESP_ERR_INVALID_STATE: Error, the TWDT has not been initialized yet
|
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_task_wdt_add(TaskHandle_t handle);
|
esp_err_t esp_task_wdt_add(TaskHandle_t handle);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Reset the Task Watchdog Timer (TWDT) on behalf of the currently
|
* @brief Reset the Task Watchdog Timer (TWDT) on behalf of the currently running task
|
||||||
* running task
|
|
||||||
*
|
*
|
||||||
* This function will reset the TWDT on behalf of the currently running task.
|
* This function will reset the TWDT on behalf of the currently running task. Each subscribed task must periodically
|
||||||
* Each subscribed task must periodically call this function to prevent the
|
* call this function to prevent the TWDT from timing out. If one or more subscribed tasks fail to reset the TWDT on
|
||||||
* TWDT from timing out. If one or more subscribed tasks fail to reset the
|
* their own behalf, a TWDT timeout will occur. If the IDLE tasks have been subscribed to the TWDT, they will
|
||||||
* TWDT on their own behalf, a TWDT timeout will occur. If the IDLE tasks have
|
* automatically call this function from their idle hooks. Calling this function from a task that has not subscribed to
|
||||||
* been subscribed to the TWDT, they will automatically call this function from
|
* the TWDT, or when the TWDT is uninitialized will result in an error code being returned.
|
||||||
* their idle hooks. Calling this function from a task that has not subscribed
|
|
||||||
* to the TWDT, or when the TWDT is uninitialized will result in an error code
|
|
||||||
* being returned.
|
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: Successfully reset the TWDT on behalf of the currently
|
* - ESP_OK: Successfully reset the TWDT on behalf of the currently running task
|
||||||
* running task
|
* - ESP_ERR_NOT_FOUND: The task is not subscribed
|
||||||
* - ESP_ERR_NOT_FOUND: Error, the current running task has not subscribed
|
* - ESP_ERR_INVALID_STATE: TWDT was never initialized
|
||||||
* to the TWDT
|
|
||||||
* - ESP_ERR_INVALID_STATE: Error, the TWDT has not been initialized yet
|
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_task_wdt_reset(void);
|
esp_err_t esp_task_wdt_reset(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Unsubscribes a task from the Task Watchdog Timer (TWDT)
|
* @brief Unsubscribes a task from the Task Watchdog Timer (TWDT)
|
||||||
*
|
*
|
||||||
* This function will unsubscribe a task from the TWDT. After being
|
* This function will unsubscribe a task from the TWDT. After being unsubscribed, the task should no longer call
|
||||||
* unsubscribed, the task should no longer call esp_task_wdt_reset(). If the
|
* esp_task_wdt_reset(). If the task is an IDLE task, this function will automatically disable the calling of
|
||||||
* task is an IDLE task, this function will automatically disable the calling
|
* esp_task_wdt_reset() from the Idle Hook. Calling this function whilst the TWDT is uninitialized or attempting to
|
||||||
* of esp_task_wdt_reset() from the Idle Hook. Calling this function whilst the
|
* unsubscribe an already unsubscribed task from the TWDT will result in an error code being returned.
|
||||||
* TWDT is uninitialized or attempting to unsubscribe an already unsubscribed
|
|
||||||
* task from the TWDT will result in an error code being returned.
|
|
||||||
*
|
|
||||||
* @param[in] handle Handle of the task. Input NULL to unsubscribe the
|
|
||||||
* current running task.
|
|
||||||
*
|
*
|
||||||
|
* @param[in] handle Handle of the task. Input NULL to unsubscribe the current running task.
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: Successfully unsubscribed the task from the TWDT
|
* - ESP_OK: Successfully unsubscribed the task from the TWDT
|
||||||
* - ESP_ERR_INVALID_ARG: Error, the task is already unsubscribed
|
* - ESP_ERR_NOT_FOUND: The task is not subscribed
|
||||||
* - ESP_ERR_INVALID_STATE: Error, the TWDT has not been initialized yet
|
* - ESP_ERR_INVALID_STATE: TWDT was never initialized
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_task_wdt_delete(TaskHandle_t handle);
|
esp_err_t esp_task_wdt_delete(TaskHandle_t handle);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Query whether a task is subscribed to the Task Watchdog Timer (TWDT)
|
* @brief Query whether a task is subscribed to the Task Watchdog Timer (TWDT)
|
||||||
*
|
*
|
||||||
* This function will query whether a task is currently subscribed to the TWDT,
|
* This function will query whether a task is currently subscribed to the TWDT, or whether the TWDT is initialized.
|
||||||
* or whether the TWDT is initialized.
|
|
||||||
*
|
|
||||||
* @param[in] handle Handle of the task. Input NULL to query the current
|
|
||||||
* running task.
|
|
||||||
*
|
*
|
||||||
|
* @param[in] handle Handle of the task. Input NULL to query the current running task.
|
||||||
* @return:
|
* @return:
|
||||||
* - ESP_OK: The task is currently subscribed to the TWDT
|
* - ESP_OK: The task is currently subscribed to the TWDT
|
||||||
* - ESP_ERR_NOT_FOUND: The task is currently not subscribed to the TWDT
|
* - ESP_ERR_NOT_FOUND: The task is not subscribed
|
||||||
* - ESP_ERR_INVALID_STATE: The TWDT is not initialized, therefore no tasks
|
* - ESP_ERR_INVALID_STATE: TWDT was never initialized
|
||||||
* can be subscribed
|
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_task_wdt_status(TaskHandle_t handle);
|
esp_err_t esp_task_wdt_status(TaskHandle_t handle);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -14,8 +14,10 @@
|
|||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include "freertos/queue.h"
|
#include "freertos/queue.h"
|
||||||
#include "freertos/semphr.h"
|
#include "freertos/semphr.h"
|
||||||
|
#include <sys/queue.h>
|
||||||
#include <esp_types.h>
|
#include <esp_types.h>
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
|
#include "esp_check.h"
|
||||||
#include "esp_intr_alloc.h"
|
#include "esp_intr_alloc.h"
|
||||||
#include "esp_attr.h"
|
#include "esp_attr.h"
|
||||||
#include "esp_debug_helpers.h"
|
#include "esp_debug_helpers.h"
|
||||||
@@ -29,50 +31,90 @@
|
|||||||
#include "hal/timer_types.h"
|
#include "hal/timer_types.h"
|
||||||
#include "hal/wdt_hal.h"
|
#include "hal/wdt_hal.h"
|
||||||
|
|
||||||
|
// --------------------------------------------------- Definitions -----------------------------------------------------
|
||||||
|
|
||||||
static const char *TAG = "task_wdt";
|
// ----------------------- Macros --------------------------
|
||||||
|
|
||||||
//Assertion macro where, if 'cond' is false, will exit the critical section and return 'ret'
|
|
||||||
#define ASSERT_EXIT_CRIT_RETURN(cond, ret) ({ \
|
|
||||||
if(!(cond)){ \
|
|
||||||
portEXIT_CRITICAL(&twdt_spinlock); \
|
|
||||||
return ret; \
|
|
||||||
} \
|
|
||||||
})
|
|
||||||
|
|
||||||
//Empty define used in ASSERT_EXIT_CRIT_RETURN macro when returning in void
|
|
||||||
#define VOID_RETURN
|
|
||||||
|
|
||||||
// HAL related variables and constants
|
// HAL related variables and constants
|
||||||
#define TWDT_INSTANCE WDT_MWDT0
|
#define TWDT_INSTANCE WDT_MWDT0
|
||||||
#define TWDT_TICKS_PER_US MWDT0_TICKS_PER_US
|
#define TWDT_TICKS_PER_US MWDT0_TICKS_PER_US
|
||||||
#define TWDT_PRESCALER MWDT0_TICK_PRESCALER // Tick period of 500us if WDT source clock is 80MHz
|
#define TWDT_PRESCALER MWDT0_TICK_PRESCALER // Tick period of 500us if WDT source clock is 80MHz
|
||||||
static wdt_hal_context_t twdt_context;
|
|
||||||
|
// ---------------------- Typedefs -------------------------
|
||||||
|
|
||||||
// Structure used for each subscribed task
|
// Structure used for each subscribed task
|
||||||
typedef struct twdt_task_t twdt_task_t;
|
typedef struct twdt_entry twdt_entry_t;
|
||||||
struct twdt_task_t {
|
struct twdt_entry {
|
||||||
|
SLIST_ENTRY(twdt_entry) slist_entry;
|
||||||
TaskHandle_t task_handle;
|
TaskHandle_t task_handle;
|
||||||
bool has_reset;
|
bool has_reset;
|
||||||
twdt_task_t *next;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Structure used to hold run time configuration of the TWDT
|
// Structure used to hold run time configuration of the TWDT
|
||||||
typedef struct twdt_config_t twdt_config_t;
|
typedef struct twdt_obj twdt_obj_t;
|
||||||
struct twdt_config_t {
|
struct twdt_obj {
|
||||||
twdt_task_t *list; //Linked list of subscribed tasks
|
wdt_hal_context_t hal;
|
||||||
uint32_t timeout; //Timeout period of TWDT
|
SLIST_HEAD(entry_list_head, twdt_entry) entries_slist;
|
||||||
bool panic; // Flag to trigger panic when TWDT times out
|
bool panic; // Flag to trigger panic when TWDT times out
|
||||||
intr_handle_t intr_handle;
|
intr_handle_t intr_handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
static twdt_config_t *twdt_config = NULL;
|
// ----------------------- Objects -------------------------
|
||||||
static portMUX_TYPE twdt_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
|
||||||
|
|
||||||
/*
|
static const char *TAG = "task_wdt";
|
||||||
* Idle hook callback for Idle Tasks to reset the TWDT. This callback will only
|
static portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||||
* be registered to the Idle Hook of a particular core when the corresponding
|
static twdt_obj_t *p_twdt_obj = NULL;
|
||||||
* Idle Task subscribes to the TWDT.
|
|
||||||
|
// ----------------------------------------------------- Private -------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Find an entry from its task handle, and checks if all other entries have been reset
|
||||||
|
*
|
||||||
|
* @param[in] handle Task handle
|
||||||
|
* @param[out] all_reset Whether all entries have been reset
|
||||||
|
* @return Entry, or NULL if not found
|
||||||
|
*/
|
||||||
|
static twdt_entry_t *find_entry_from_handle_and_check_all_reset(TaskHandle_t handle, bool *all_reset)
|
||||||
|
{
|
||||||
|
twdt_entry_t *target = NULL;
|
||||||
|
bool found_non_reset = false;
|
||||||
|
|
||||||
|
twdt_entry_t *entry;
|
||||||
|
SLIST_FOREACH(entry, &p_twdt_obj->entries_slist, slist_entry) {
|
||||||
|
if (entry->task_handle == handle) {
|
||||||
|
target = entry;
|
||||||
|
} else if (entry->has_reset == false) {
|
||||||
|
found_non_reset = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*all_reset = !found_non_reset;
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reset hardware timer and entry flags
|
||||||
|
*/
|
||||||
|
static void reset_hw_timer(void)
|
||||||
|
{
|
||||||
|
// All tasks have reset; time to reset the hardware timer.
|
||||||
|
wdt_hal_write_protect_disable(&p_twdt_obj->hal);
|
||||||
|
wdt_hal_feed(&p_twdt_obj->hal);
|
||||||
|
wdt_hal_write_protect_enable(&p_twdt_obj->hal);
|
||||||
|
//C lear the has_reset flag in each entry
|
||||||
|
twdt_entry_t *entry;
|
||||||
|
SLIST_FOREACH(entry, &p_twdt_obj->entries_slist, slist_entry) {
|
||||||
|
entry->has_reset = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Idle hook callback
|
||||||
|
*
|
||||||
|
* Idle hook callback for Idle Tasks to reset the TWDT. This callback will only be registered to the Idle Hook of a
|
||||||
|
* particular core when the corresponding Idle Task subscribes to the TWDT.
|
||||||
|
*
|
||||||
|
* @return Always returns true
|
||||||
*/
|
*/
|
||||||
static bool idle_hook_cb(void)
|
static bool idle_hook_cb(void)
|
||||||
{
|
{
|
||||||
@@ -80,101 +122,75 @@ static bool idle_hook_cb(void)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Internal function that looks for the target task in the TWDT task list.
|
* @brief User ISR callback placeholder
|
||||||
* Returns the list item if found and returns null if not found. Also checks if
|
*
|
||||||
* all the other tasks have reset. Should be called within critical.
|
* This function is called by task_wdt_isr function (ISR for when TWDT times out). It can be redefined in user code to
|
||||||
*/
|
* handle twdt events.
|
||||||
static twdt_task_t *find_task_in_twdt_list(TaskHandle_t handle, bool *all_reset)
|
*
|
||||||
{
|
* @note It has the same limitations as the interrupt function. Do not use ESP_LOGI functions inside.
|
||||||
twdt_task_t *target = NULL;
|
|
||||||
*all_reset = true;
|
|
||||||
for(twdt_task_t *task = twdt_config->list; task != NULL; task = task->next){
|
|
||||||
if(task->task_handle == handle){
|
|
||||||
target = task; //Get pointer to target task list member
|
|
||||||
}else{
|
|
||||||
if(task->has_reset == false){ //If a task has yet to reset
|
|
||||||
*all_reset = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Resets the hardware timer and has_reset flags of each task on the list.
|
|
||||||
* Called within critical
|
|
||||||
*/
|
|
||||||
static void reset_hw_timer(void)
|
|
||||||
{
|
|
||||||
//All tasks have reset; time to reset the hardware timer.
|
|
||||||
wdt_hal_write_protect_disable(&twdt_context);
|
|
||||||
wdt_hal_feed(&twdt_context);
|
|
||||||
wdt_hal_write_protect_enable(&twdt_context);
|
|
||||||
//Clear all has_reset flags in list
|
|
||||||
for (twdt_task_t *task = twdt_config->list; task != NULL; task = task->next){
|
|
||||||
task->has_reset=false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This function is called by task_wdt_isr function (ISR for when TWDT times out).
|
|
||||||
* It can be redefined in user code to handle twdt events.
|
|
||||||
* Note: It has the same limitations as the interrupt function.
|
|
||||||
* Do not use ESP_LOGI functions inside.
|
|
||||||
*/
|
*/
|
||||||
void __attribute__((weak)) esp_task_wdt_isr_user_handler(void)
|
void __attribute__((weak)) esp_task_wdt_isr_user_handler(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* ISR for when TWDT times out. Checks for which tasks have not reset. Also
|
* @brief TWDT timeout ISR function
|
||||||
* triggers panic if configured to do so
|
*
|
||||||
|
* Tee ISR checks which entries have not been reset, prints some debugging information, and triggers a panic if
|
||||||
|
* configured to do so.
|
||||||
|
*
|
||||||
|
* @param arg ISR argument
|
||||||
*/
|
*/
|
||||||
static void task_wdt_isr(void *arg)
|
static void task_wdt_isr(void *arg)
|
||||||
{
|
{
|
||||||
portENTER_CRITICAL_ISR(&twdt_spinlock);
|
portENTER_CRITICAL_ISR(&spinlock);
|
||||||
twdt_task_t *twdttask;
|
|
||||||
const char *cpu;
|
|
||||||
// Reset hardware timer so that 2nd stage timeout is not reached (will trigger system reset)
|
// Reset hardware timer so that 2nd stage timeout is not reached (will trigger system reset)
|
||||||
wdt_hal_write_protect_disable(&twdt_context);
|
wdt_hal_write_protect_disable(&p_twdt_obj->hal);
|
||||||
wdt_hal_handle_intr(&twdt_context); //Feeds WDT and clears acknowledges interrupt
|
wdt_hal_handle_intr(&p_twdt_obj->hal); // Feeds WDT and clears acknowledges interrupt
|
||||||
wdt_hal_write_protect_enable(&twdt_context);
|
wdt_hal_write_protect_enable(&p_twdt_obj->hal);
|
||||||
|
// If there are no entries, there's nothing to do.
|
||||||
//We are taking a spinlock while doing I/O (ESP_EARLY_LOGE) here. Normally, that is a pretty
|
if (SLIST_EMPTY(&p_twdt_obj->entries_slist)) {
|
||||||
//bad thing, possibly (temporarily) hanging up the 2nd core and stopping FreeRTOS. In this case,
|
portEXIT_CRITICAL_ISR(&spinlock);
|
||||||
//something bad already happened and reporting this is considered more important
|
return;
|
||||||
//than the badness caused by a spinlock here.
|
}
|
||||||
|
// Find what entries triggered the TWDT timeout (i.e., which entries have not been reset)
|
||||||
//Return immediately if no tasks have been added to task list
|
/*
|
||||||
ASSERT_EXIT_CRIT_RETURN((twdt_config->list != NULL), VOID_RETURN);
|
Note: We are currently in a critical section, thus under normal circumstances, logging should not be allowed.
|
||||||
|
However, TWDT timeouts count as fatal errors, thus reporting the fatal error is considered more important than
|
||||||
//Watchdog got triggered because at least one task did not reset in time.
|
minimizing interrupt latency. Thus we allow logging in critical sections in this narrow case.
|
||||||
|
*/
|
||||||
ESP_EARLY_LOGE(TAG, "Task watchdog got triggered. The following tasks did not reset the watchdog in time:");
|
ESP_EARLY_LOGE(TAG, "Task watchdog got triggered. The following tasks did not reset the watchdog in time:");
|
||||||
for (twdttask=twdt_config->list; twdttask!=NULL; twdttask=twdttask->next) {
|
twdt_entry_t *entry;
|
||||||
if (!twdttask->has_reset) {
|
SLIST_FOREACH(entry, &p_twdt_obj->entries_slist, slist_entry) {
|
||||||
cpu=xTaskGetAffinity(twdttask->task_handle)==0?DRAM_STR("CPU 0"):DRAM_STR("CPU 1");
|
if (!entry->has_reset) {
|
||||||
if (xTaskGetAffinity(twdttask->task_handle)==tskNO_AFFINITY) {
|
BaseType_t task_affinity = xTaskGetAffinity(entry->task_handle);
|
||||||
|
const char *cpu;
|
||||||
|
if (task_affinity == 0) {
|
||||||
|
cpu = DRAM_STR("CPU 0");
|
||||||
|
} else if (task_affinity == 1) {
|
||||||
|
cpu = DRAM_STR("CPU 1");
|
||||||
|
} else {
|
||||||
cpu = DRAM_STR("CPU 0/1");
|
cpu = DRAM_STR("CPU 0/1");
|
||||||
}
|
}
|
||||||
ESP_EARLY_LOGE(TAG, " - %s (%s)", pcTaskGetName(twdttask->task_handle), cpu);
|
ESP_EARLY_LOGE(TAG, " - %s (%s)", pcTaskGetName(entry->task_handle), cpu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ESP_EARLY_LOGE(TAG, "%s", DRAM_STR("Tasks currently running:"));
|
ESP_EARLY_LOGE(TAG, "%s", DRAM_STR("Tasks currently running:"));
|
||||||
for (int x = 0; x < portNUM_PROCESSORS; x++) {
|
for (int x = 0; x < portNUM_PROCESSORS; x++) {
|
||||||
ESP_EARLY_LOGE(TAG, "CPU %d: %s", x, pcTaskGetName(xTaskGetCurrentTaskHandleForCPU(x)));
|
ESP_EARLY_LOGE(TAG, "CPU %d: %s", x, pcTaskGetName(xTaskGetCurrentTaskHandleForCPU(x)));
|
||||||
}
|
}
|
||||||
|
portEXIT_CRITICAL_ISR(&spinlock);
|
||||||
|
|
||||||
|
// Run user ISR handler
|
||||||
esp_task_wdt_isr_user_handler();
|
esp_task_wdt_isr_user_handler();
|
||||||
|
// Trigger configured timeout behavior (e.g., panic or print backtrace)
|
||||||
if (twdt_config->panic){ //Trigger Panic if configured to do so
|
if (p_twdt_obj->panic) {
|
||||||
ESP_EARLY_LOGE(TAG, "Aborting.");
|
ESP_EARLY_LOGE(TAG, "Aborting.");
|
||||||
portEXIT_CRITICAL_ISR(&twdt_spinlock);
|
|
||||||
esp_reset_reason_set_hint(ESP_RST_TASK_WDT);
|
esp_reset_reason_set_hint(ESP_RST_TASK_WDT);
|
||||||
abort();
|
abort();
|
||||||
} else {
|
} else { // Print
|
||||||
|
|
||||||
#if !CONFIG_IDF_TARGET_ESP32C3 && !CONFIG_IDF_TARGET_ESP32H2 && !CONFIG_IDF_TARGET_ESP32C2 // TODO: ESP32-C3 IDF-2986
|
#if !CONFIG_IDF_TARGET_ESP32C3 && !CONFIG_IDF_TARGET_ESP32H2 && !CONFIG_IDF_TARGET_ESP32C2 // TODO: ESP32-C3 IDF-2986
|
||||||
int current_core = xPortGetCoreID();
|
int current_core = xPortGetCoreID();
|
||||||
// Print backtrace of current core
|
// Print backtrace of current core
|
||||||
@@ -188,175 +204,167 @@ static void task_wdt_isr(void *arg)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
portEXIT_CRITICAL_ISR(&twdt_spinlock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// ----------------------------------------------------- Public --------------------------------------------------------
|
||||||
* Initializes the TWDT by allocating memory for the config data
|
|
||||||
* structure, obtaining the idle task handles/registering idle hooks, and
|
|
||||||
* setting the hardware timer registers. If reconfiguring, it will just modify
|
|
||||||
* wdt_config and reset the hardware timer.
|
|
||||||
*/
|
|
||||||
esp_err_t esp_task_wdt_init(uint32_t timeout, bool panic)
|
esp_err_t esp_task_wdt_init(uint32_t timeout, bool panic)
|
||||||
{
|
{
|
||||||
portENTER_CRITICAL(&twdt_spinlock);
|
esp_err_t ret;
|
||||||
if(twdt_config == NULL){ //TWDT not initialized yet
|
|
||||||
//Allocate memory for wdt_config
|
|
||||||
twdt_config = calloc(1, sizeof(twdt_config_t));
|
|
||||||
ASSERT_EXIT_CRIT_RETURN((twdt_config != NULL), ESP_ERR_NO_MEM);
|
|
||||||
|
|
||||||
twdt_config->list = NULL;
|
|
||||||
twdt_config->timeout = timeout;
|
|
||||||
twdt_config->panic = panic;
|
|
||||||
|
|
||||||
//Register Interrupt and ISR
|
|
||||||
ESP_ERROR_CHECK(esp_intr_alloc(ETS_TG0_WDT_LEVEL_INTR_SOURCE, 0, task_wdt_isr, NULL, &twdt_config->intr_handle));
|
|
||||||
|
|
||||||
|
twdt_obj_t *obj = NULL;
|
||||||
|
if (p_twdt_obj == NULL) {
|
||||||
|
// Allocate and initialize TWDT driver object
|
||||||
|
obj = calloc(1, sizeof(twdt_obj_t));
|
||||||
|
ESP_GOTO_ON_FALSE((obj != NULL), ESP_ERR_NO_MEM, err, TAG, "insufficient memory");
|
||||||
|
SLIST_INIT(&obj->entries_slist);
|
||||||
|
obj->panic = panic;
|
||||||
|
ESP_ERROR_CHECK(esp_intr_alloc(ETS_TG0_WDT_LEVEL_INTR_SOURCE, 0, task_wdt_isr, NULL, &obj->intr_handle));
|
||||||
|
portENTER_CRITICAL(&spinlock);
|
||||||
// Configure hardware timer
|
// Configure hardware timer
|
||||||
periph_module_enable(PERIPH_TIMG0_MODULE);
|
periph_module_enable(PERIPH_TIMG0_MODULE);
|
||||||
wdt_hal_init(&twdt_context, TWDT_INSTANCE, TWDT_PRESCALER, true);
|
wdt_hal_init(&obj->hal, TWDT_INSTANCE, TWDT_PRESCALER, true);
|
||||||
wdt_hal_write_protect_disable(&twdt_context);
|
// Assign the driver object
|
||||||
//Configure 1st stage timeout and behavior
|
p_twdt_obj = obj;
|
||||||
wdt_hal_config_stage(&twdt_context, WDT_STAGE0, twdt_config->timeout * (1000000 / TWDT_TICKS_PER_US), WDT_STAGE_ACTION_INT);
|
portEXIT_CRITICAL(&spinlock);
|
||||||
//Configure 2nd stage timeout and behavior
|
|
||||||
wdt_hal_config_stage(&twdt_context, WDT_STAGE1, twdt_config->timeout * (2 * 1000000 / TWDT_TICKS_PER_US), WDT_STAGE_ACTION_RESET_SYSTEM);
|
|
||||||
//Enable the WDT
|
|
||||||
wdt_hal_enable(&twdt_context);
|
|
||||||
wdt_hal_write_protect_enable(&twdt_context);
|
|
||||||
} else { //twdt_config previously initialized
|
|
||||||
//Reconfigure task wdt
|
|
||||||
twdt_config->panic = panic;
|
|
||||||
twdt_config->timeout = timeout;
|
|
||||||
|
|
||||||
//Reconfigure hardware timer
|
|
||||||
wdt_hal_write_protect_disable(&twdt_context);
|
|
||||||
wdt_hal_disable(&twdt_context);
|
|
||||||
wdt_hal_config_stage(&twdt_context, WDT_STAGE0, twdt_config->timeout * (1000 * 1000 / TWDT_TICKS_PER_US), WDT_STAGE_ACTION_INT);
|
|
||||||
wdt_hal_config_stage(&twdt_context, WDT_STAGE1, twdt_config->timeout * (2 * 1000 * 1000 / TWDT_TICKS_PER_US), WDT_STAGE_ACTION_RESET_SYSTEM);
|
|
||||||
wdt_hal_enable(&twdt_context);
|
|
||||||
wdt_hal_write_protect_enable(&twdt_context);
|
|
||||||
}
|
}
|
||||||
portEXIT_CRITICAL(&twdt_spinlock);
|
portENTER_CRITICAL(&spinlock);
|
||||||
return ESP_OK;
|
wdt_hal_write_protect_disable(&p_twdt_obj->hal);
|
||||||
|
// Configure 1st stage timeout and behavior
|
||||||
|
wdt_hal_config_stage(&p_twdt_obj->hal, WDT_STAGE0, timeout * (1000000 / TWDT_TICKS_PER_US), WDT_STAGE_ACTION_INT);
|
||||||
|
// Configure 2nd stage timeout and behavior
|
||||||
|
wdt_hal_config_stage(&p_twdt_obj->hal, WDT_STAGE1, timeout * (2 * 1000000 / TWDT_TICKS_PER_US), WDT_STAGE_ACTION_RESET_SYSTEM);
|
||||||
|
// Enable the WDT
|
||||||
|
wdt_hal_enable(&p_twdt_obj->hal);
|
||||||
|
wdt_hal_write_protect_enable(&p_twdt_obj->hal);
|
||||||
|
portEXIT_CRITICAL(&spinlock);
|
||||||
|
ret = ESP_OK;
|
||||||
|
err:
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t esp_task_wdt_deinit(void)
|
esp_err_t esp_task_wdt_deinit(void)
|
||||||
{
|
{
|
||||||
portENTER_CRITICAL(&twdt_spinlock);
|
esp_err_t ret;
|
||||||
//TWDT must already be initialized
|
|
||||||
ASSERT_EXIT_CRIT_RETURN((twdt_config != NULL), ESP_ERR_NOT_FOUND);
|
|
||||||
//Task list must be empty
|
|
||||||
ASSERT_EXIT_CRIT_RETURN((twdt_config->list == NULL), ESP_ERR_INVALID_STATE);
|
|
||||||
|
|
||||||
//Disable hardware timer
|
portENTER_CRITICAL(&spinlock);
|
||||||
wdt_hal_deinit(&twdt_context);
|
// Check TWDT state
|
||||||
|
ESP_GOTO_ON_FALSE((p_twdt_obj != NULL), ESP_ERR_INVALID_STATE, err, TAG, "task watchdog was never initialized");
|
||||||
|
ESP_GOTO_ON_FALSE(SLIST_EMPTY(&p_twdt_obj->entries_slist), ESP_ERR_INVALID_STATE, err, TAG, "all tasks must be deleted");
|
||||||
|
// Disable hardware timer and the interrupt
|
||||||
|
wdt_hal_write_protect_disable(&p_twdt_obj->hal);
|
||||||
|
wdt_hal_disable(&p_twdt_obj->hal);
|
||||||
|
wdt_hal_write_protect_enable(&p_twdt_obj->hal);
|
||||||
|
wdt_hal_deinit(&p_twdt_obj->hal);
|
||||||
|
esp_intr_disable(p_twdt_obj->intr_handle);
|
||||||
|
// Unassign driver object
|
||||||
|
twdt_obj_t *obj = p_twdt_obj;
|
||||||
|
p_twdt_obj = NULL;
|
||||||
|
portEXIT_CRITICAL(&spinlock);
|
||||||
|
|
||||||
ESP_ERROR_CHECK(esp_intr_free(twdt_config->intr_handle)); //Unregister interrupt
|
// Free driver resources
|
||||||
free(twdt_config); //Free twdt_config
|
ESP_ERROR_CHECK(esp_intr_free(obj->intr_handle)); //Deregister interrupt
|
||||||
twdt_config = NULL;
|
free(obj); //Free p_twdt_obj
|
||||||
portEXIT_CRITICAL(&twdt_spinlock);
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
|
|
||||||
|
err:
|
||||||
|
portEXIT_CRITICAL(&spinlock);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t esp_task_wdt_add(TaskHandle_t handle)
|
esp_err_t esp_task_wdt_add(TaskHandle_t handle)
|
||||||
{
|
{
|
||||||
portENTER_CRITICAL(&twdt_spinlock);
|
esp_err_t ret;
|
||||||
//TWDT must already be initialized
|
|
||||||
ASSERT_EXIT_CRIT_RETURN((twdt_config != NULL), ESP_ERR_INVALID_STATE);
|
|
||||||
|
|
||||||
twdt_task_t *target_task;
|
|
||||||
bool all_reset;
|
|
||||||
if (handle == NULL) { //Get handle of current task if none is provided
|
if (handle == NULL) { //Get handle of current task if none is provided
|
||||||
handle = xTaskGetCurrentTaskHandle();
|
handle = xTaskGetCurrentTaskHandle();
|
||||||
}
|
}
|
||||||
//Check if tasks exists in task list, and if all other tasks have reset
|
|
||||||
target_task = find_task_in_twdt_list(handle, &all_reset);
|
|
||||||
//task cannot be already subscribed
|
|
||||||
ASSERT_EXIT_CRIT_RETURN((target_task == NULL), ESP_ERR_INVALID_ARG);
|
|
||||||
|
|
||||||
//Add target task to TWDT task list
|
// Allocate entry for task
|
||||||
target_task = calloc(1,sizeof(twdt_task_t));
|
twdt_entry_t *entry = calloc(1, sizeof(twdt_entry_t));
|
||||||
ASSERT_EXIT_CRIT_RETURN((target_task != NULL), ESP_ERR_NO_MEM);
|
ESP_GOTO_ON_FALSE((entry != NULL), ESP_ERR_NO_MEM, alloc_err, TAG, "insufficient memory");
|
||||||
target_task->task_handle = handle;
|
entry->task_handle = handle;
|
||||||
target_task->has_reset = true;
|
entry->has_reset = false;
|
||||||
target_task->next = NULL;
|
|
||||||
if (twdt_config->list == NULL) { //Adding to empty list
|
|
||||||
twdt_config->list = target_task;
|
|
||||||
} else { //Adding to tail of list
|
|
||||||
twdt_task_t *task;
|
|
||||||
for (task = twdt_config->list; task->next != NULL; task = task->next){
|
|
||||||
; //point task to current tail of TWDT task list
|
|
||||||
}
|
|
||||||
task->next = target_task;
|
|
||||||
}
|
|
||||||
|
|
||||||
//If idle task, register the idle hook callback to appropriate core
|
portENTER_CRITICAL(&spinlock);
|
||||||
|
// Check TWDT state
|
||||||
|
ESP_GOTO_ON_FALSE((p_twdt_obj != NULL), ESP_ERR_INVALID_STATE, state_err, TAG, "task watchdog was never initialized");
|
||||||
|
// Check if the task is an entry, and if all entries have been reset
|
||||||
|
bool all_reset;
|
||||||
|
twdt_entry_t *found_entry = find_entry_from_handle_and_check_all_reset(handle, &all_reset);
|
||||||
|
ESP_GOTO_ON_FALSE((found_entry == NULL), ESP_ERR_INVALID_ARG, state_err, TAG, "task is already subscribed");
|
||||||
|
// Add task to entry list
|
||||||
|
SLIST_INSERT_HEAD(&p_twdt_obj->entries_slist, entry, slist_entry);
|
||||||
|
if (all_reset) { //Reset hardware timer if all other tasks in list have reset in
|
||||||
|
reset_hw_timer();
|
||||||
|
}
|
||||||
|
portEXIT_CRITICAL(&spinlock); //Nested critical if Legacy
|
||||||
|
|
||||||
|
// If the task was the idle task, register the idle hook callback to appropriate core
|
||||||
for (int i = 0; i < portNUM_PROCESSORS; i++) {
|
for (int i = 0; i < portNUM_PROCESSORS; i++) {
|
||||||
if (handle == xTaskGetIdleTaskHandleForCPU(i)) {
|
if (handle == xTaskGetIdleTaskHandleForCPU(i)) {
|
||||||
ESP_ERROR_CHECK(esp_register_freertos_idle_hook_for_cpu(idle_hook_cb, i));
|
ESP_ERROR_CHECK(esp_register_freertos_idle_hook_for_cpu(idle_hook_cb, i));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(all_reset){ //Reset hardware timer if all other tasks in list have reset in
|
|
||||||
reset_hw_timer();
|
|
||||||
}
|
|
||||||
|
|
||||||
portEXIT_CRITICAL(&twdt_spinlock); //Nested critical if Legacy
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
|
|
||||||
|
state_err:
|
||||||
|
portEXIT_CRITICAL(&spinlock);
|
||||||
|
free(entry);
|
||||||
|
alloc_err:
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t esp_task_wdt_reset(void)
|
esp_err_t esp_task_wdt_reset(void)
|
||||||
{
|
{
|
||||||
portENTER_CRITICAL(&twdt_spinlock);
|
esp_err_t ret;
|
||||||
//TWDT must already be initialized
|
|
||||||
ASSERT_EXIT_CRIT_RETURN((twdt_config != NULL), ESP_ERR_INVALID_STATE);
|
|
||||||
|
|
||||||
TaskHandle_t handle = xTaskGetCurrentTaskHandle();
|
TaskHandle_t handle = xTaskGetCurrentTaskHandle();
|
||||||
twdt_task_t *target_task;
|
|
||||||
|
portENTER_CRITICAL(&spinlock);
|
||||||
|
// Check TWDT state
|
||||||
|
ESP_GOTO_ON_FALSE((p_twdt_obj != NULL), ESP_ERR_INVALID_STATE, err, TAG, "task watchdog was never initialized");
|
||||||
|
// Find entry for task
|
||||||
bool all_reset;
|
bool all_reset;
|
||||||
|
twdt_entry_t *entry;
|
||||||
//Check if task exists in task list, and if all other tasks have reset
|
entry = find_entry_from_handle_and_check_all_reset(handle, &all_reset);
|
||||||
target_task = find_task_in_twdt_list(handle, &all_reset);
|
ESP_GOTO_ON_FALSE((entry != NULL), ESP_ERR_NOT_FOUND, err, TAG, "task not found");
|
||||||
//Return error if trying to reset task that is not on the task list
|
// Mark entry as reset and issue timer reset if all entries have been reset
|
||||||
ASSERT_EXIT_CRIT_RETURN((target_task != NULL), ESP_ERR_NOT_FOUND);
|
entry->has_reset = true; //Reset the task if it's on the task list
|
||||||
|
|
||||||
target_task->has_reset = true; //Reset the task if it's on the task list
|
|
||||||
if (all_reset) { //Reset if all other tasks in list have reset in
|
if (all_reset) { //Reset if all other tasks in list have reset in
|
||||||
reset_hw_timer();
|
reset_hw_timer();
|
||||||
}
|
}
|
||||||
|
ret = ESP_OK;
|
||||||
|
err:
|
||||||
|
portEXIT_CRITICAL(&spinlock);
|
||||||
|
|
||||||
portEXIT_CRITICAL(&twdt_spinlock);
|
return ret;
|
||||||
return ESP_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t esp_task_wdt_delete(TaskHandle_t handle)
|
esp_err_t esp_task_wdt_delete(TaskHandle_t handle)
|
||||||
{
|
{
|
||||||
|
esp_err_t ret;
|
||||||
if (handle == NULL) {
|
if (handle == NULL) {
|
||||||
handle = xTaskGetCurrentTaskHandle();
|
handle = xTaskGetCurrentTaskHandle();
|
||||||
}
|
}
|
||||||
portENTER_CRITICAL(&twdt_spinlock);
|
|
||||||
//Return error if twdt has not been initialized
|
|
||||||
ASSERT_EXIT_CRIT_RETURN((twdt_config != NULL), ESP_ERR_NOT_FOUND);
|
|
||||||
|
|
||||||
twdt_task_t *target_task;
|
portENTER_CRITICAL(&spinlock);
|
||||||
|
// Check TWDT state
|
||||||
|
ESP_GOTO_ON_FALSE((p_twdt_obj != NULL), ESP_ERR_INVALID_STATE, err, TAG, "task watchdog was never initialized");
|
||||||
|
// Find entry for task
|
||||||
bool all_reset;
|
bool all_reset;
|
||||||
target_task = find_task_in_twdt_list(handle, &all_reset);
|
twdt_entry_t *entry;
|
||||||
//Task doesn't exist on list. Return error
|
entry = find_entry_from_handle_and_check_all_reset(handle, &all_reset);
|
||||||
ASSERT_EXIT_CRIT_RETURN((target_task != NULL), ESP_ERR_INVALID_ARG);
|
ESP_GOTO_ON_FALSE((entry != NULL), ESP_ERR_NOT_FOUND, err, TAG, "task not found");
|
||||||
|
// Remove entry
|
||||||
if(target_task == twdt_config->list){ //target_task is head of list. Delete
|
SLIST_REMOVE(&p_twdt_obj->entries_slist, entry, twdt_entry, slist_entry);
|
||||||
twdt_config->list = target_task->next;
|
// Reset hardware timer if all remaining tasks have reset
|
||||||
free(target_task);
|
if (all_reset) {
|
||||||
}else{ //target_task not head of list. Delete
|
reset_hw_timer();
|
||||||
twdt_task_t *prev;
|
|
||||||
for (prev = twdt_config->list; prev->next != target_task; prev = prev->next){
|
|
||||||
; //point prev to task preceding target_task
|
|
||||||
}
|
|
||||||
prev->next = target_task->next;
|
|
||||||
free(target_task);
|
|
||||||
}
|
}
|
||||||
|
portEXIT_CRITICAL(&spinlock);
|
||||||
|
|
||||||
|
// Free the entry
|
||||||
|
free(entry);
|
||||||
// If idle task, deregister idle hook callback form appropriate core
|
// If idle task, deregister idle hook callback form appropriate core
|
||||||
for (int i = 0; i < portNUM_PROCESSORS; i++) {
|
for (int i = 0; i < portNUM_PROCESSORS; i++) {
|
||||||
if (handle == xTaskGetIdleTaskHandleForCPU(i)) {
|
if (handle == xTaskGetIdleTaskHandleForCPU(i)) {
|
||||||
@@ -364,32 +372,31 @@ esp_err_t esp_task_wdt_delete(TaskHandle_t handle)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(all_reset){ //Reset hardware timer if all remaining tasks have reset
|
|
||||||
reset_hw_timer();
|
|
||||||
}
|
|
||||||
|
|
||||||
portEXIT_CRITICAL(&twdt_spinlock);
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
|
|
||||||
|
err:
|
||||||
|
portEXIT_CRITICAL(&spinlock);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t esp_task_wdt_status(TaskHandle_t handle)
|
esp_err_t esp_task_wdt_status(TaskHandle_t handle)
|
||||||
{
|
{
|
||||||
|
esp_err_t ret;
|
||||||
if (handle == NULL) {
|
if (handle == NULL) {
|
||||||
handle = xTaskGetCurrentTaskHandle();
|
handle = xTaskGetCurrentTaskHandle();
|
||||||
}
|
}
|
||||||
|
|
||||||
portENTER_CRITICAL(&twdt_spinlock);
|
portENTER_CRITICAL(&spinlock);
|
||||||
//Return if TWDT is not initialized
|
// Check TWDT state
|
||||||
ASSERT_EXIT_CRIT_RETURN((twdt_config != NULL), ESP_ERR_INVALID_STATE);
|
ESP_GOTO_ON_FALSE((p_twdt_obj != NULL), ESP_ERR_INVALID_STATE, err, TAG, "task watchdog was never initialized");
|
||||||
|
// Find entry for task
|
||||||
|
bool all_reset;
|
||||||
|
twdt_entry_t *entry;
|
||||||
|
entry = find_entry_from_handle_and_check_all_reset(handle, &all_reset);
|
||||||
|
(void) all_reset; // Unused
|
||||||
|
ret = (entry != NULL) ? ESP_OK : ESP_ERR_NOT_FOUND;
|
||||||
|
err:
|
||||||
|
portEXIT_CRITICAL(&spinlock);
|
||||||
|
|
||||||
twdt_task_t *task;
|
return ret;
|
||||||
for(task = twdt_config->list; task!=NULL; task=task->next){
|
|
||||||
//Return ESP_OK if task is found
|
|
||||||
ASSERT_EXIT_CRIT_RETURN((task->task_handle != handle), ESP_OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Task could not be found
|
|
||||||
portEXIT_CRITICAL(&twdt_spinlock);
|
|
||||||
return ESP_ERR_NOT_FOUND;
|
|
||||||
}
|
}
|
||||||
|
@@ -676,7 +676,6 @@ components/esp_system/include/esp_private/startup_internal.h
|
|||||||
components/esp_system/include/esp_private/system_internal.h
|
components/esp_system/include/esp_private/system_internal.h
|
||||||
components/esp_system/include/esp_private/usb_console.h
|
components/esp_system/include/esp_private/usb_console.h
|
||||||
components/esp_system/include/esp_task.h
|
components/esp_system/include/esp_task.h
|
||||||
components/esp_system/include/esp_task_wdt.h
|
|
||||||
components/esp_system/port/arch/riscv/expression_with_stack.c
|
components/esp_system/port/arch/riscv/expression_with_stack.c
|
||||||
components/esp_system/port/arch/xtensa/expression_with_stack.c
|
components/esp_system/port/arch/xtensa/expression_with_stack.c
|
||||||
components/esp_system/port/public_compat/brownout.h
|
components/esp_system/port/public_compat/brownout.h
|
||||||
|
Reference in New Issue
Block a user