Watchdog RTC
Watchdog, também conhecido como o “cão de guarda”, ele
basicamente é um temporizador que fica verificando o funcionamento
de um sistema. Ele precisa ser rearmado dentro de um limite de
tempo, senão, o microcontrolador é automaticamente reiniciado.
O Watchdog RTC é o mais confiável porque faz uma análise
completa do sistema, sendo capaz de reiniciar completamente todo o
ESP32 garantindo que todo sistema não fique travado. Causas possíveis
de travamento: ruídos de alimentação, ruídos de acionamentos de
relés, queda de energia e sobretensão, falha de CPU, falhas de
software, hardware e etc.
A importância do uso de um watchdog?
Vamos supor que você faça um projeto de monitoramento de
temperatura de umas câmaras frias que armazenam medicamentos e
vacinas caras. O ESP32 deve monitorar os sensores de temperatura e
enviar os dados por um servidor de internet. De forma alguma essas
câmaras devem ultrapassar uma certa temperatura para que não estrague
os medicamentos e vacinas.
Caso ocorra uma elevação de temperatura, ele deve enviar
imediatamente um aviso para que se resolva a situação o mais rápido
possível. E se ele travar? E se estiver mandando dados errados ?
Imagina o prejuízo ? Para piorar a situação, esse projeto foi feito
numa área bem longe. O que é mais fácil ? Dar o reset manual ou
instalar uma sistema de Watchdog ?
Sketch da programação
Descarregue o sketch abaixo no seu ESP32. Explicações logo
abaixo.
#include <rtc_wdt.h>
void setup() {
//Inicia o Serial para debug
Serial.begin(115200);
watchdogRTC(); //Habilita o watchdog
}
void watchdogRTC()
{
rtc_wdt_protect_off(); //Desabilita a proteção
rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_RESET_RTC);
rtc_wdt_set_time(RTC_WDT_STAGE0, 9000); // define o tempo do timer em milissegundos
rtc_wdt_enable(); // Inicia o temporizador
rtc_wdt_protect_on(); // habilitar proteção
}
void loop () {
rtc_wdt_feed ();
if (Serial.available())
{
while(1){
Serial.println("teste watchdog");
delay(1000);
}
}
}
Primeiro, adicionamos a biblioteca responsável.
#include <rtc_wdt.h>
Logo em seguida, habilitamos a função no setup.
watchdogRTC(); //Habilita o watchdog
Declaramos a função responsável WatchdogRTC ().
void watchdogRTC()
{
rtc_wdt_protect_off(); // Desabilita o watchdog
rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_RESET_RTC);
rtc_wdt_set_time(RTC_WDT_STAGE0, 9000);
rtc_wdt_enable(); //habilita o watchdog. Inicia a contagem do timer
rtc_wdt_protect_on(); // Habilita o RTC WDT
}
Único parâmetro que devemos ajustar é rtc_wdt_set_time.
rtc_wdt_set_time(RTC_WDT_STAGE0, 9000);
Aqui definimos o tempo em milissegundos que ele deve atuar.
Nesse caso, colocamos o temporizador pra 9 segundos.
Lembrando que o máximo de tempo é 120000 milissegundos( 120
segundos).
Se ele não for alimentado ou resetado até 9 segundos, ele
reinicia o ESP32.
Agora no loop(), está a função de reset do watchdog. Toda vez
que o loop rodar o sistema, automaticamente ele vai alimentar o
watchdog. Caso contrário, após 9 segundos, se essa função não for
executada, o ESP32 é reiniciado.
void loop () {
rtc_wdt_feed ();
Apenas para testarmos se o watchdog está funcionado, criamos a
função abaixo para simularmos um travamento.
if (Serial.available())
{
while(1){
Serial.println("teste watchdog");
delay(1000);
}
}
Se digitarmos qualquer coisa no monitor serial, ele vai printar
“ teste Watchdog” a cada 1 segundo. Enquanto estiver preso nessa
função While(1),ou seja, enquanto houver algo escrito no monitor
serial e não estiver resetando o watchdog pela função rtc_wdt_feed (); no
loop, ele vai printar 9 vezes e o ESP32 vai ser reiniciado.
Vamos fazer o teste. Abra o seu monitor serial. Digite qualquer
coisa e aperte “Enter”. Note que após 9 vezes, ele será reiniciado.
Watchdog RTC em 2 núcleos do ESP32
Vejamos agora como devemos usar a proteção watchdog no ESP32
quando estivermos usando os dois núcleos de processamento.
Sketch da programação
Descarregue o sketch abaixo no seu ESP32. Explicações logo
abaixo.
#include <rtc_wdt.h>
TaskHandle_t Tarefa1;
TaskHandle_t Tarefa2;
void setup() {
//Inicia o Serial para debug
Serial.begin(115200);
// crie uma tarefa que será executada na função Tarefa1codigo(), com prioridade 1 e
executada no núcleo 0
xTaskCreatePinnedToCore(
Tarefa1codigo, /* Função da tarefa. */
"Tarefa1", /* nome da tarefa. */
10000, /* Tamanho da pilha da tarefa */
NULL, /* parâmetro da tarefa */
1, /* prioridade da tarefa */
&Tarefa1, /* Alça de tarefa para manter o controle da tarefa
criada */
0); /* fixar tarefa no núcleo 0 */
//crie uma tarefa que será executada na função Tarefa2codigo(), com prioridade 1 e
executada no núcleo 1
xTaskCreatePinnedToCore(
Tarefa2codigo, /* Função da tarefa. */
"Tarefa2", /* nome da tarefa. */
10000, /* Tamanho da pilha da tarefa */
NULL, /* parâmetro da tarefa */
1, /* prioridade da tarefa */
&Tarefa2, /* Alça de tarefa para manter o controle da tarefa
criada */
1); /* fixar tarefa no núcleo 1 */
watchdogRTC();
void Tarefa1codigo( void * pvParameters ){
Serial.println("Núcleo 1 rodando....");
Serial.println(xPortGetCoreID());
for(;;){
Serial.println("nucleo 1 ok");
delay(7000);
}
}
void Tarefa2codigo( void * pvParameters ){
Serial.println("Núcleo 2 rodando....");
Serial.println(xPortGetCoreID());
for(;;){
Serial.println("nucleo 2 ok");
delay(7000);
}
}
void watchdogRTC()
{
rtc_wdt_protect_off();
rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_RESET_RTC);
rtc_wdt_set_time(RTC_WDT_STAGE0, 4000);
rtc_wdt_enable();
rtc_wdt_protect_on();
}
void loop () {
rtc_wdt_feed ();
if (Serial.available())
{
while(1){
Serial.println("teste watchdog");
delay(1000);
}
}
}
Já vimos anteriormente como usamos os dois núcleos de
processamento do ESP32. Apenas vamos incluir as funções do Watchdog.
A inclusão da biblioteca responsável pelo Watchdog.
#include <rtc_wdt.h>
Precisamos declarar os nomes das tarefas que vamos executar:
TaskHandle_t Tarefa1;
TaskHandle_t Tarefa2;
Logo em seguida, na função setup(), vamos criar as 2 tarefas:
xTaskCreatePinnedToCore(): função para criar as tarefas
xTaskCreatePinnedToCore(
Tarefa1codigo, // nome da função que vai ser chamada pela tarefa
"Tarefa1", // nome da tarefa
10000, // Tamanho da pilha da tarefa
NULL, // parâmetro da tarefa para executar uma função (void)
1, // prioridade da tarefa de 1 até 25 níveis. Quanto mais alto o valor,
maior a prioridade.
&Tarefa1, // identificador da tarefa, deve ser igual ao nome da tarefa.
0); // qual núcleo a tarefa deve ser rodada.
xTaskCreatePinnedToCore(
Tarefa2codigo, // nome da função que vai ser chamada pela tarefa
"Tarefa2", // nome da tarefa
10000, // Tamanho da pilha da tarefa
NULL, // parâmetro da tarefa para executar uma função (void)
1, // prioridade da tarefa de 1 até 25 níveis. Quanto mais alto o valor,
maior a prioridade.
&Tarefa2, // identificador da tarefa, deve ser igual ao nome da tarefa.
1); // qual núcleo a tarefa deve ser rodada.
Ainda no setup, declaramos a função WatchdogRTC.
watchdogRTC();
Agora fora do setup, criamos as 2 funções que serão chamadas
pelas tarefas que criamos:
void Tarefa1codigo( void * pvParameters ){
Serial.println("Núcleo 1 rodando....");
Serial.println(xPortGetCoreID());
for(;;){
Serial.println("nucleo 1 ok");
delay(7000);
}
}
A tarefa 1 vai printar na serial “núcleo 1 ok” a cada 7
segundos.
void Tarefa2codigo( void * pvParameters ){
Serial.println("Núcleo 2 rodando....");
Serial.println(xPortGetCoreID());
for(;;){
Serial.println("nucleo 2 ok");
delay(7000);
}
}
Na tarefa 2, vamos fazer a mesma coisa, printar “núcleo 2 ok”
a cada 7 segundos.
void watchdogRTC()
{
rtc_wdt_protect_off();
rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_RESET_RTC);
rtc_wdt_set_time(RTC_WDT_STAGE0, 4000);
rtc_wdt_enable();
rtc_wdt_protect_on();
}
Declaramos a função Watchdog no sistema antes do Loop. Agora
coloquei o temporizador pra 4 segundos.
void loop () {
rtc_wdt_feed ();
if (Serial.available())
{
while(1){
Serial.println("teste watchdog");
delay(1000);
}
}
}
No loop, colocamos a função de alimentação do watchdog,
rtc_wdt_feed (); .
Se digitarmos qualquer coisa no monitor serial, ele vai printar
“ teste Watchdog” a cada 1 segundo. Enquanto estiver preso nessa
função While(1),ou seja, enquanto houver algo escrito no monitor
serial e não estiver resetando o watchdog pela função rtc_wdt_feed (); no
loop, ele vai printar 4 vezes e o ESP32 vai ser reiniciado.
Vamos fazer o teste. Abra o seu monitor serial. Digite qualquer
coisa e aperte “Enter”. Note que após 4 vezes, ele será reiniciado.
***Observação: Dependendo do código que vai usar nas tarefas 1
e 2, há a necessidade de colocar um delay(100) pra que ele não fique
reiniciando.