ESP32 ESP-IDF看门狗TWDT

陈拓 2022/07/02-2022/07/02

1. 概述

此示例演示如何使用任务看门狗计时器Task Watchdog Timer (TWDT)的以下功能:

  • 如何初始化和取消初始化TWDT
  • 如何订阅和取消订阅TWDT的任务
  • 如何向阅和取消订阅TWDT的用户
  • 如何使任务和用户可以重置(即喂狗)TWDTs

2. 官方例程国内镜像

https://gitee.com/EspressifSystems/esp-idf/tree/master/examples/system/task_watchdog

3. 开发环境

《用乐鑫国内Gitee镜像搭建ESP32开发环境》

https://zhuanlan.zhihu.com/p/348106034

https://blog.csdn.net/chentuo2000/article/details/113424934?spm=1001.2014.3001.5501

4. 复制代码

  • 克隆官方例程

将官方例子项目复制到ESP-IDF开发工具之外:

cd ~/esp

cp -r ~/esp/esp-idf/examples/system/task_watchdog ~/esp/

  • 项目树

cd ~/esp/task_watchdog

tree

5. 构建项目

  • 刷新esp-idf环境

get_idf

  • 设定目标芯片

idf.py set-target esp32

  • 配置项目

idf.py menuconfig

1) 将闪存设置为4MB

2) 在任务看门狗超时时调用紧急处理程序

保存,退出。

  • 编译项目

idf.py build

  • 烧写项目

查看USB转串口的COM口号:

烧写:

idf.py -p /dev/ttyS3 -b 115200 flash

  • 启用监视器

idf.py monitor -p /dev/ttyS3

当示例正常运行时,将观察到以下输出:

用户可以注释掉esp_task_wdt_reset()或esp_task_wdt_reset_user()调用以测试触发TWDT,

//CHECK_ERROR_CODE(esp_task_wdt_reset(), ESP_OK);

这将导致以下输出:

看门狗被触发。

因为TWDT超时时间为3秒:

#define TWDT_TIMEOUT_S          3 // TWDT超时时间

延时为10秒:

vTaskDelay(pdMS_TO_TICKS(10000));   // 延时10

在10秒延时期间,看门狗有3次触发,之后程序会继续执行:

6. 看门狗触发后立即重启程序

如果你希望任务看门狗触发之后进行重启

  • 设置在任务看门狗超时时调用紧急处理程序

  • 增加esp_task_wdt_isr_user_handler()函数
void esp_task_wdt_isr_user_handler(void)
{
    esp_restart();
}

这样在看门狗触发时程序会重新启动:

7. 完整代码

/* Task_Watchdog Examples

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_task_wdt.h"

#define TWDT_TIMEOUT_S          3 // TWDT超时时间
#define TASK_RESET_PERIOD_S     2 // 任务重置周期时间

/*
 * 宏,用于检查TWDT的输出,如果检测到返回错误码则触发中止程序执行。
 */
#define CHECK_ERROR_CODE(returned, expected) ({                        \
            if(returned != expected){                                  \
                printf("TWDT ERROR\n");                                \
                abort();                                               \
            }                                                          \
})

static TaskHandle_t task_handles[portNUM_PROCESSORS];

// 回调由app_main()创建的用户任务
void reset_task(void *arg)
{
    // 为TWDT添加任务,并检查dwt状态看是否添加
    CHECK_ERROR_CODE(esp_task_wdt_add(NULL), ESP_OK);
    CHECK_ERROR_CODE(esp_task_wdt_status(NULL), ESP_OK);

    while(1){
        // 每2秒重置一次看门狗
        //CHECK_ERROR_CODE(esp_task_wdt_reset(), ESP_OK);  // 喂狗。注释此行以测试触发TWDT超时
        vTaskDelay(pdMS_TO_TICKS(TASK_RESET_PERIOD_S * 1000));
    }
}

void esp_task_wdt_isr_user_handler(void)
{
    esp_restart();
}

void app_main(void)
{
    printf("Initialize TWDT\n");
    // 初始化或者重新初始化TWDT
    CHECK_ERROR_CODE(esp_task_wdt_init(TWDT_TIMEOUT_S, false), ESP_OK);

    // 如果启动时未订阅空闲任务,则将其订阅到TWDT
#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

    // 创建用户任务并添加到看门狗
    for(int i = 0; i < portNUM_PROCESSORS; i++){
        xTaskCreatePinnedToCore(reset_task, "reset task", 1024, NULL, 10, &task_handles[i], i);
    }

    printf("Delay for 10 seconds\n");
    vTaskDelay(pdMS_TO_TICKS(10000));   // 延时10秒

    printf("Unsubscribing and deleting tasks\n");
    // 从任务看门狗中删除并取消订阅用户任务,然后取消订阅空闲任务
    for(int i = 0; i < portNUM_PROCESSORS; i++){
        vTaskDelete(task_handles[i]);   // 首先删除用户任务(防止重置未订阅的任务)
        CHECK_ERROR_CODE(esp_task_wdt_delete(task_handles[i]), ESP_OK); // 从TWDT取消订阅任务
        CHECK_ERROR_CODE(esp_task_wdt_status(task_handles[i]), ESP_ERR_NOT_FOUND);  // 确认任务已取消订阅

        // 取消订阅空闲任务
        CHECK_ERROR_CODE(esp_task_wdt_delete(xTaskGetIdleTaskHandleForCPU(i)), ESP_OK); // 从TWDT取消订阅空闲任务
        CHECK_ERROR_CODE(esp_task_wdt_status(xTaskGetIdleTaskHandleForCPU(i)), ESP_ERR_NOT_FOUND); // 确认空闲任务已取消订阅
    }

    // 在所有任务取消订阅后取消TWDT
    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 确认TWDT已解除初始化

    printf("Complete\n");
}

参考文档

  1. ESP32任务看门狗实践https://www.codeleading.com/article/25393323890/

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晨之清风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值