1
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
33
34
37
41
42
46
47
48
49
50
51
52
53
54
55
56
57
60
61
62
63
64
79
80
88
89
90
91
92
93
94
95
96
97
100
101
104
105
106
107
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
142
143
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
187
188
193
194
195
196
197
208
209
210
211
212
213
214
217
218
223
224
225
226
227
228
229
230
231
232
235
236
242
243
244
/* ... */
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include "sdkconfig.h"
#include "hal/wdt_hal.h"
#include "hal/mwdt_ll.h"
#include "hal/timer_ll.h"
#include "esp_check.h"
#include "esp_err.h"
#include "esp_attr.h"
#include "esp_intr_alloc.h"
#include "esp_log.h"
#include "esp_private/system_internal.h"
#include "esp_private/periph_ctrl.h"
#include "esp_private/esp_task_wdt_impl.h"15 includes
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_TIMER_SUPPORT_SLEEP_RETENTION
#include "esp_private/sleep_retention.h"
#endif
#define TWDT_INSTANCE WDT_MWDT0
#define TWDT_TICKS_PER_US 500
#define TWDT_PRESCALER MWDT_LL_DEFAULT_CLK_PRESCALER
#define TWDT_PERIPH_MODULE PERIPH_TIMG0_MODULE
#define TWDT_TIMER_GROUP 0
#define TWDT_INTR_SOURCE ETS_TG0_WDT_LEVEL_INTR_SOURCE6 defines
/* ... */
typedef struct {
wdt_hal_context_t hal;
intr_handle_t intr_handle;
}{ ... } twdt_ctx_hard_t;
/* ... */
static twdt_ctx_hard_t init_context;
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_TIMER_SUPPORT_SLEEP_RETENTION
static const char* TAG = "task_wdt";
static esp_err_t sleep_task_wdt_retention_init(void *arg)
{
uint32_t group_id = *(uint32_t *)arg;
esp_err_t err = sleep_retention_entries_create(tg_wdt_regs_retention[group_id].link_list,
tg_wdt_regs_retention[group_id].link_num,
REGDMA_LINK_PRI_SYS_PERIPH_LOW,
(group_id == 0) ? SLEEP_RETENTION_MODULE_TG0_WDT : SLEEP_RETENTION_MODULE_TG1_WDT);
if (err == ESP_OK) {
ESP_LOGD(TAG, "Task watchdog timer retention initialization");
}{...}
ESP_RETURN_ON_ERROR(err, TAG, "Failed to create sleep retention linked list for task watchdog timer");
return err;
}{...}
static esp_err_t esp_task_wdt_retention_enable(uint32_t group_id)
{
sleep_retention_module_init_param_t init_param = {
.cbs = { .create = { .handle = sleep_task_wdt_retention_init, .arg = &group_id } },
.depends = RETENTION_MODULE_BITMAP_INIT(CLOCK_SYSTEM)
}{...};
esp_err_t err = sleep_retention_module_init((group_id == 0) ? SLEEP_RETENTION_MODULE_TG0_WDT : SLEEP_RETENTION_MODULE_TG1_WDT, &init_param);
if (err == ESP_OK) {
err = sleep_retention_module_allocate((group_id == 0) ? SLEEP_RETENTION_MODULE_TG0_WDT : SLEEP_RETENTION_MODULE_TG1_WDT);
if (err != ESP_OK) {
ESP_LOGW(TAG, "Failed to allocate sleep retention linked list for task watchdog timer retention");
}{...}
}{...}
return err;
}{...}
static esp_err_t esp_task_wdt_retention_disable(uint32_t group_id)
{
esp_err_t err = sleep_retention_module_free((group_id == 0) ? SLEEP_RETENTION_MODULE_TG0_WDT : SLEEP_RETENTION_MODULE_TG1_WDT);
if (err == ESP_OK) {
err = sleep_retention_module_deinit((group_id == 0) ? SLEEP_RETENTION_MODULE_TG0_WDT : SLEEP_RETENTION_MODULE_TG1_WDT);
}{...}
return err;
}{...}
/* ... */#endif
esp_err_t esp_task_wdt_impl_timer_allocate(const esp_task_wdt_config_t *config,
twdt_isr_callback callback,
twdt_ctx_t *obj)
{
esp_err_t ret = ESP_OK;
twdt_ctx_hard_t *ctx = &init_context;
if (config == NULL || obj == NULL) {
ret = ESP_ERR_INVALID_STATE;
}{...}
if (ret == ESP_OK) {
esp_intr_alloc(TWDT_INTR_SOURCE, 0, callback, NULL, &ctx->intr_handle);
}{...}
if (ret == ESP_OK) {
PERIPH_RCC_ACQUIRE_ATOMIC(TWDT_PERIPH_MODULE, ref_count) {
if (ref_count == 0) {
timer_ll_enable_bus_clock(TWDT_TIMER_GROUP, true);
timer_ll_reset_register(TWDT_TIMER_GROUP);
}{...}
}{...}
wdt_hal_init(&ctx->hal, TWDT_INSTANCE, TWDT_PRESCALER, true);
wdt_hal_write_protect_disable(&ctx->hal);
wdt_hal_config_stage(&ctx->hal, WDT_STAGE0, config->timeout_ms * (1000 / TWDT_TICKS_PER_US), WDT_STAGE_ACTION_INT);
wdt_hal_config_stage(&ctx->hal, WDT_STAGE1, config->timeout_ms * (2 * 1000 / TWDT_TICKS_PER_US), WDT_STAGE_ACTION_RESET_SYSTEM);
wdt_hal_write_protect_enable(&ctx->hal);
*obj = (twdt_ctx_t) ctx;
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_TIMER_SUPPORT_SLEEP_RETENTION
esp_task_wdt_retention_enable(TWDT_TIMER_GROUP);
#endif
}{...}
return ret;
}{ ... }
esp_err_t esp_task_wdt_impl_timer_reconfigure(twdt_ctx_t obj, const esp_task_wdt_config_t *config)
{
esp_err_t ret = ESP_OK;
twdt_ctx_hard_t* ctx = (twdt_ctx_hard_t*) obj;
if (config == NULL || ctx == NULL) {
ret = ESP_ERR_INVALID_STATE;
}{...}
if (ret == ESP_OK) {
wdt_hal_write_protect_disable(&ctx->hal);
wdt_hal_config_stage(&ctx->hal, WDT_STAGE0, config->timeout_ms * (1000 / TWDT_TICKS_PER_US), WDT_STAGE_ACTION_INT);
wdt_hal_config_stage(&ctx->hal, WDT_STAGE1, config->timeout_ms * (2 * 1000 / TWDT_TICKS_PER_US), WDT_STAGE_ACTION_RESET_SYSTEM);
wdt_hal_write_protect_enable(&ctx->hal);
}{...}
return ret;
}{ ... }
void esp_task_wdt_impl_timer_free(twdt_ctx_t obj)
{
twdt_ctx_hard_t* ctx = (twdt_ctx_hard_t*) obj;
if (ctx != NULL) {
wdt_hal_deinit(&ctx->hal);
ESP_ERROR_CHECK(esp_intr_disable(ctx->intr_handle));
PERIPH_RCC_RELEASE_ATOMIC(TWDT_PERIPH_MODULE, ref_count) {
if (ref_count == 0) {
timer_ll_enable_bus_clock(TWDT_TIMER_GROUP, false);
}{...}
}{...}
ESP_ERROR_CHECK(esp_intr_free(ctx->intr_handle));
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_TIMER_SUPPORT_SLEEP_RETENTION
ESP_ERROR_CHECK(esp_task_wdt_retention_disable(TWDT_TIMER_GROUP));
#endif
}{...}
}{ ... }
esp_err_t esp_task_wdt_impl_timer_feed(twdt_ctx_t obj)
{
esp_err_t ret = ESP_OK;
twdt_ctx_hard_t* ctx = (twdt_ctx_hard_t*) obj;
if (ctx == NULL) {
ret = ESP_ERR_INVALID_STATE;
}{...}
if (ret == ESP_OK) {
wdt_hal_write_protect_disable(&ctx->hal);
wdt_hal_feed(&ctx->hal);
wdt_hal_write_protect_enable(&ctx->hal);
}{...}
return ret;
}{ ... }
void esp_task_wdt_impl_timeout_triggered(twdt_ctx_t obj)
{
twdt_ctx_hard_t* ctx = (twdt_ctx_hard_t*) obj;
if (ctx != NULL) {
wdt_hal_write_protect_disable(&ctx->hal);
wdt_hal_handle_intr(&ctx->hal);
wdt_hal_write_protect_enable(&ctx->hal);
}{...}
}{ ... }
esp_err_t esp_task_wdt_impl_timer_stop(twdt_ctx_t obj)
{
esp_err_t ret = ESP_OK;
twdt_ctx_hard_t* ctx = (twdt_ctx_hard_t*) obj;
if (ctx == NULL) {
ret = ESP_ERR_INVALID_STATE;
}{...}
if (ret == ESP_OK) {
wdt_hal_write_protect_disable(&ctx->hal);
wdt_hal_disable(&ctx->hal);
wdt_hal_write_protect_enable(&ctx->hal);
}{...}
return ret;
}{ ... }
esp_err_t esp_task_wdt_impl_timer_restart(twdt_ctx_t obj)
{
esp_err_t ret = ESP_OK;
twdt_ctx_hard_t* ctx = (twdt_ctx_hard_t*) obj;
if (ctx == NULL) {
ret = ESP_ERR_INVALID_STATE;
}{...}
if (ret == ESP_OK) {
wdt_hal_write_protect_disable(&ctx->hal);
wdt_hal_enable(&ctx->hal);
wdt_hal_feed(&ctx->hal);
wdt_hal_write_protect_enable(&ctx->hal);
}{...}
return ret;
}{ ... }