Freertos学习07-看门狗

发布时间 2023-07-01 22:04:10作者: seekwhale13

一、前言

看门狗是一种硬件计时器,用于监控系统的运行状态。它可以在系统出现故障或停止响应时自动重启系统,以确保系统的稳定性和可靠性。ESP-IDF 支持多种类型的看门狗,其中两种主要类型是:中断看门狗定时器和任务看门狗定时器 (TWDT)。中断看门狗定时器和 TWDT 都可以使用项目配置菜单启用,但 TWDT 也可以在运行时启用。中断看门狗负责检测 FreeRTOS 任务切换长时间受阻的实例。TWDT 负责检测长时间运行而不产生任务的实例。

二、看门狗介绍

1.中断看门狗(IWDT)

  中断看门狗(IWDT) 的目的是确保中断服务程序(ISR)不会被长时间阻止运行,如果中断服务程序不能及时运行,一是会导致中断任务被延迟(一般的中断任务都比较重要,需要及时执行);二会导致任务无法切换(任务调度在中断里执行)。
  当中断看门狗被触发时,默认操作是调用紧急处理程序,并将紧急原因显示为 OR。根据紧急处理程序配置的行为,用户可以调试IWDT超时的来源(通过回溯,OpenOCD,gdbstub等)或简单地重置芯片。

2.任务看门狗(TWDT)

  任务监视计时器(TWDT)用于监视特定任务,确保它们能够在给定的超时时间内执行。TWDT主要监视每个CPU的空闲任务,但是任何任务都可以订阅由TWDT监视。通过观察每个CPU的空闲任务,TWDT可以检测到长时间运行而释放CPU的任务实例。
  TWDT是围绕定时器组0中的硬件看门狗定时器构建的。当发生超时时,会触发中断。用户可以在用户代码中定义函数esp_task_wdt_isr_user_handler,用来接收超时事件并制定应对策略。

三、看门狗API

1.订阅任务看门狗

esp_err_t esp_task_wdt_add(TaskHandle_t task_handle)

  将任务加入看门狗(TWDT)监视。
  此函数为TWDT订阅任务。每个订阅的任务都必须定期调用esp_task_wdt_reset(),以防止TWDT超时。否则将导致TWDT超时。
  参数:task_handle,任务的句柄。输入NULL将当前正在运行的任务订阅到TWDT。
  返回值:

  • ESP_OK:已成功将任务订阅到TWDT
  • Other:订阅任务失败

2.重置看门狗

image

四、代码测试

1.IDLE未及时执行情形

  在前面的task状态打印中我们已知IDLE任务的优先级为0,处于最低的优先级,而IDLE是一个喂狗函数,如果未在规定时间内(这里设置了5s)运行IDLE喂狗,单片机将会异常重启。
image

#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "driver/gpio.h"
#include "esp_task_wdt.h"

void blinke_slow(void *pvparam)
{
	while (1)
	{
		;
		// printf("靓仔\n");
		// vTaskDelay(1000 / portTICK_PERIOD_MS); // 延时
	}
}

void app_main(void)
{

	TaskHandle_t xHandle = NULL;
	xTaskCreate(blinke_slow, "mytask1", 1024, NULL, 1, &xHandle);
}

  打印信息如下:第二行表示IDLE函数为未及时运行触发了看门狗,第四行表示触发看门狗时正在运行的是mytask1,这种情况解决办法有两种:一是调高IDLE函数的优先级,使其有资格共享CPU时间片;二是在优先级高的任务中加入延时函数,使其进入阻塞态,此时CPU会运行其他优先级低的任务,两种办法本质上都是让IDLE函数得到CPU时间片运行。
image

2.添加用户函数进入监控行列

  有时候我们需要保证某个函数必须执行,我们可以将我们编写的函数进入看门狗监控列表,一旦发生异常,任务无法顺利执行,看门狗产生异常信号。

#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "driver/gpio.h"
#include "esp_task_wdt.h"

void blinke_slow(void *pvparam)
{
	while (1)
	{

		printf("靓仔\n");
		vTaskDelay(1000 / portTICK_PERIOD_MS); // 延时
		esp_task_wdt_reset();//喂狗
	}
}

void app_main(void)
{

	TaskHandle_t xHandle = NULL;
	xTaskCreate(blinke_slow, "mytask1", 1024, NULL, 1, &xHandle);
	esp_task_wdt_add(xHandle);//将mytask1加入看门狗监控列表i

}


THE END!