Skip to content

Commit

Permalink
Merge branch 'feature/add_int_task_wdt_esp32c2' into 'master'
Browse files Browse the repository at this point in the history
WDT: implement interrupt wdt and task wdt for ESP32-C2

Closes IDF-4035, IDF-4205, and IDF-5055

See merge request espressif/esp-idf!18918
  • Loading branch information
o-marshmallow committed Sep 16, 2022
2 parents 1146b83 + 79598b1 commit 4f1a9e4
Show file tree
Hide file tree
Showing 45 changed files with 1,046 additions and 206 deletions.
2 changes: 1 addition & 1 deletion .gitlab/ci/target-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1015,7 +1015,7 @@ UT_S2_SDSPI:

UT_C2:
extends: .unit_test_esp32c2_template
parallel: 21
parallel: 22
tags:
- ESP32C2_IDF
- UT_T1_1
Expand Down
3 changes: 0 additions & 3 deletions components/esp_event/test/test_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@
#include "test_utils.h"


#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32C2)
//IDF-4035
static const char* TAG = "test_event";

#define TEST_CONFIG_ITEMS_TO_REGISTER 5
Expand Down Expand Up @@ -2021,4 +2019,3 @@ TEST_CASE("can post events from interrupt handler", "[event]")
}

#endif // CONFIG_ESP_EVENT_POST_FROM_ISR
#endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP32C2)
16 changes: 16 additions & 0 deletions components/esp_hw_support/sleep_modes.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#include "esp_private/sleep_retention.h"
#include "esp_private/esp_clk.h"
#include "esp_private/startup_internal.h"
#include "esp_private/esp_task_wdt.h"

#ifdef CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/cache.h"
Expand Down Expand Up @@ -663,6 +664,13 @@ static inline bool can_power_down_vddsdio(const uint32_t vddsdio_pd_sleep_durati

esp_err_t esp_light_sleep_start(void)
{
#if CONFIG_ESP_TASK_WDT_USE_ESP_TIMER
esp_err_t timerret = ESP_OK;

/* If a task watchdog timer is running, we have to stop it. */
timerret = esp_task_wdt_stop();
#endif // CONFIG_ESP_TASK_WDT_USE_ESP_TIMER

s_config.ccount_ticks_record = esp_cpu_get_cycle_count();
static portMUX_TYPE light_sleep_lock = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL(&light_sleep_lock);
Expand Down Expand Up @@ -821,6 +829,14 @@ esp_err_t esp_light_sleep_start(void)
}
portEXIT_CRITICAL(&light_sleep_lock);
s_config.sleep_time_overhead_out = (esp_cpu_get_cycle_count() - s_config.ccount_ticks_record) / (esp_clk_cpu_freq() / 1000000ULL);

#if CONFIG_ESP_TASK_WDT_USE_ESP_TIMER
/* Restart the Task Watchdog timer as it was stopped before sleeping. */
if (timerret == ESP_OK) {
esp_task_wdt_restart();
}
#endif // CONFIG_ESP_TASK_WDT_USE_ESP_TIMER

return err;
}

Expand Down
10 changes: 9 additions & 1 deletion components/esp_pm/linker.lf
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,24 @@ entries:
freertos_hooks:esp_vApplicationIdleHook (noflash)
if PM_SLP_IRAM_OPT = y:
task_wdt:idle_hook_cb (noflash)
task_wdt:reset_hw_timer (noflash)
task_wdt:task_wdt_timer_feed (noflash)
task_wdt:find_entry_and_check_all_reset (noflash)
task_wdt:find_entry_from_task_handle_and_check_all_reset (noflash)
task_wdt:esp_task_wdt_reset (noflash)
task_wdt:esp_task_wdt_reset_user (noflash)
if ESP_TASK_WDT_USE_ESP_TIMER = y:
task_wdt_impl_esp_timer:esp_task_wdt_impl_timer_feed (noflash)
else:
task_wdt_impl_timergroup:esp_task_wdt_impl_timer_feed (noflash)

[mapping:esp_timer_pm]
archive: libesp_timer.a
entries:
if PM_SLP_IRAM_OPT = y:
# esp_timer_feed is called from task_wdt_timer_feed, so put it
# in IRAM if task_wdt_timer_feed itself is in IRAM.
if ESP_TASK_WDT_USE_ESP_TIMER = y:
esp_timer:esp_timer_feed (noflash)
if ESP_TIMER_IMPL_TG0_LAC = y:
esp_timer_impl_lac:esp_timer_impl_lock (noflash)
esp_timer_impl_lac:esp_timer_impl_unlock (noflash)
Expand Down
11 changes: 10 additions & 1 deletion components/esp_system/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,20 @@ else()
"startup.c"
"system_time.c"
"stack_check.c"
"task_wdt.c"
"ubsan.c"
"xt_wdt.c"
"debug_stubs.c")

if(CONFIG_ESP_TASK_WDT_EN)
list(APPEND srcs "task_wdt/task_wdt.c")

if(CONFIG_ESP_TASK_WDT_USE_ESP_TIMER)
list(APPEND srcs "task_wdt/task_wdt_impl_esp_timer.c")
else()
list(APPEND srcs "task_wdt/task_wdt_impl_timergroup.c")
endif()
endif()

if(CONFIG_ESP_SYSTEM_USE_EH_FRAME)
list(APPEND srcs "eh_frame_parser.c")
endif()
Expand Down
38 changes: 27 additions & 11 deletions components/esp_system/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,6 @@ menu "ESP System Settings"

config ESP_INT_WDT
bool "Interrupt watchdog"
default n if IDF_TARGET_ESP32C2 # add support in IDF-4114
default y
help
This watchdog timer can detect if the FreeRTOS tick interrupt has not been called for a certain time,
Expand All @@ -394,19 +393,36 @@ menu "ESP System Settings"
help
Also detect if interrupts on CPU 1 are disabled for too long.

config ESP_TASK_WDT
bool "Initialize Task Watchdog Timer on startup"
config ESP_TASK_WDT_EN
bool "Enable Task Watchdog Timer"
default y
select FREERTOS_ENABLE_TASK_SNAPSHOT
help
The Task Watchdog Timer can be used to make sure individual tasks are still
running. Enabling this option will cause the Task Watchdog Timer to be
initialized automatically at startup. The Task Watchdog timer can be
initialized after startup as well (see Task Watchdog Timer API Reference)
running. Enabling this option will enable the Task Watchdog Timer. It can be
either initialized automatically at startup or initialized after startup
(see Task Watchdog Timer API Reference)

config ESP_TASK_WDT_USE_ESP_TIMER
# Software implementation of Task Watchdog, handy for targets with only a single
# Timer Group, such as the ESP32-C2
bool
depends on ESP_TASK_WDT_EN
default y if IDF_TARGET_ESP32C2
default n if !IDF_TARGET_ESP32C2
select ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD

config ESP_TASK_WDT_INIT
bool "Initialize Task Watchdog Timer on startup"
depends on ESP_TASK_WDT_EN
default y
help
Enabling this option will cause the Task Watchdog Timer to be initialized
automatically at startup.

config ESP_TASK_WDT_PANIC
bool "Invoke panic handler on Task Watchdog timeout"
depends on ESP_TASK_WDT
depends on ESP_TASK_WDT_INIT
default n
help
If this option is enabled, the Task Watchdog Timer will be configured to
Expand All @@ -415,7 +431,7 @@ menu "ESP System Settings"

config ESP_TASK_WDT_TIMEOUT_S
int "Task Watchdog timeout period (seconds)"
depends on ESP_TASK_WDT
depends on ESP_TASK_WDT_INIT
range 1 60
default 5
help
Expand All @@ -424,7 +440,7 @@ menu "ESP System Settings"

config ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0
bool "Watch CPU0 Idle Task"
depends on ESP_TASK_WDT
depends on ESP_TASK_WDT_INIT
default y
help
If this option is enabled, the Task Watchdog Timer will watch the CPU0
Expand All @@ -435,10 +451,10 @@ menu "ESP System Settings"

config ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1
bool "Watch CPU1 Idle Task"
depends on ESP_TASK_WDT && !FREERTOS_UNICORE
depends on ESP_TASK_WDT_INIT && !FREERTOS_UNICORE
default y
help
If this option is enabled, the Task Wtachdog Timer will wach the CPU1
If this option is enabled, the Task Watchdog Timer will wach the CPU1
Idle Task.

config ESP_XT_WDT
Expand Down
4 changes: 4 additions & 0 deletions components/esp_system/crosscore_int.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,14 @@ static void IRAM_ATTR esp_crosscore_isr(void *arg) {
esp_backtrace_print(100);
}

#if CONFIG_ESP_TASK_WDT_EN
if (my_reason_val & REASON_TWDT_ABORT) {
extern void task_wdt_timeout_abort_xtensa(bool);
/* Called from a crosscore interrupt, thus, we are not the core that received
* the TWDT interrupt, call the function with `false` as a parameter. */
task_wdt_timeout_abort_xtensa(false);
}
#endif // CONFIG_ESP_TASK_WDT_EN
#endif // CONFIG_IDF_TARGET_ARCH_XTENSA
}

Expand Down Expand Up @@ -171,7 +173,9 @@ void IRAM_ATTR esp_crosscore_int_send_print_backtrace(int core_id)
esp_crosscore_int_send(core_id, REASON_PRINT_BACKTRACE);
}

#if CONFIG_ESP_TASK_WDT_EN
void IRAM_ATTR esp_crosscore_int_send_twdt_abort(int core_id) {
esp_crosscore_int_send(core_id, REASON_TWDT_ABORT);
}
#endif // CONFIG_ESP_TASK_WDT_EN
#endif
5 changes: 4 additions & 1 deletion components/esp_system/include/esp_private/crosscore_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ void esp_crosscore_int_send_gdb_call(int core_id);
*/
void esp_crosscore_int_send_print_backtrace(int core_id);

#if CONFIG_ESP_TASK_WDT_EN
/**
* Send an interrupt to a CPU indicating it call `task_wdt_timeout_abort_xtensa`.
* This will make the CPU abort, using the interrupted task frame.
Expand All @@ -72,7 +73,9 @@ void esp_crosscore_int_send_print_backtrace(int core_id);
* @param core_id Core that should abort
*/
void esp_crosscore_int_send_twdt_abort(int core_id);
#endif

#endif // CONFIG_ESP_TASK_WDT_EN
#endif // !CONFIG_IDF_TARGET_ESP32C3 && !CONFIG_IDF_TARGET_ESP32H2 && !CONFIG_IDF_TARGET_ESP32C2

#ifdef __cplusplus
}
Expand Down
22 changes: 22 additions & 0 deletions components/esp_system/include/esp_private/esp_int_wdt.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,32 @@

#pragma once

#include "system_internal.h"
#include "soc/periph_defs.h"

#ifdef __cplusplus
extern "C" {
#endif

#if SOC_TIMER_GROUPS > 1

/* If we have two hardware timer groups, use the second one for interrupt watchdog. */
#define WDT_LEVEL_INTR_SOURCE ETS_TG1_WDT_LEVEL_INTR_SOURCE
#define IWDT_PRESCALER MWDT1_TICK_PRESCALER // Tick period of 500us if WDT source clock is 80MHz
#define IWDT_TICKS_PER_US MWDT1_TICKS_PER_US
#define IWDT_INSTANCE WDT_MWDT1
#define IWDT_INITIAL_TIMEOUT_S 5

#else

#define WDT_LEVEL_INTR_SOURCE ETS_TG0_WDT_LEVEL_INTR_SOURCE
#define IWDT_PRESCALER MWDT0_TICK_PRESCALER // Tick period of 500us if WDT source clock is 80MHz
#define IWDT_TICKS_PER_US MWDT0_TICKS_PER_US
#define IWDT_INSTANCE WDT_MWDT0
#define IWDT_INITIAL_TIMEOUT_S 5

#endif // SOC_TIMER_GROUPS > 1

/**
* @brief Initialize the non-CPU-specific parts of interrupt watchdog.
*
Expand Down
57 changes: 57 additions & 0 deletions components/esp_system/include/esp_private/esp_task_wdt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

#pragma once

#include "sdkconfig.h"
#include "esp_err.h"

#if CONFIG_ESP_TASK_WDT_EN

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief Type used to define the context of a Task WatchDog Timer implementation.
* This is used internally in the TWDT driver, it is implementation specific.
*/
typedef void* twdt_ctx_t;

/**
* @brief Type of the function used as an ISR callback.
*/
typedef void (*twdt_isr_callback)(void*);

/**
* @brief Stop the Task Watchdog Timer (TWDT)
*
* This function will temporarily stop the timer until it is restarted by a call to esp_task_wdt_restart().
* @note esp_task_wdt_stop() must not be called by multiple tasks simultaneously.
* @return
* - ESP_OK: TWDT successfully stopped
* - Other: Failed to stop the TWDT
*/
esp_err_t esp_task_wdt_stop(void);

/**
* @brief Restart the Task Watchdog Timer (TWDT)
*
* This function will restart the timer after it has been stopped by esp_task_wdt_stop().
* @note esp_task_wdt_restart() must not be called by multiple tasks simultaneously.
* @return
* - ESP_OK: TWDT successfully stopped
* - Other: Failed to stop the TWDT
*/
esp_err_t esp_task_wdt_restart(void);

#ifdef __cplusplus
}
#endif

#endif // CONFIG_ESP_TASK_WDT_EN
Loading

0 comments on commit 4f1a9e4

Please sign in to comment.