Servindo Watchdog adequadamente

Watchdog

Watchdogs são fundamentais em produtos, são eles que devem reiniciar o sistema a um estado conhecido na ocorrência de um comportamento anômalo. Entretanto, existe uma dificuldade considerável em fazer com que o sistema sempre seja reiniciado na ocorrência de travamentos e, no final das contas, os watchdogs são difíceis de usar e frequentemente vemos produtos congelando com seus watchdogs não atuando. Neste post eu vou apresentar a maneira correta de se programar um bom watchdog e, inclusive, vou fornecer o código da minha biblioteca de watchdog. Basta copiar e usar!

 

 

Como não fazer com Watchdog

 

  1. Servir o watchdog numa interrupção de timer: se a execução do código entrar em loop ou deadlock o watchdog continuará a ser alimentado, pois as interrupções continuarão ocorrendo;
  2. Servir várias vezes o watchdog dentro do código: quanto mais vezes a função que serve o watchdog for chamada no código, maior a probabilidade de se ter uma delas na fila de execução quando o código trancar em loop;
  3. Colocar as rotinas de delay para servir o watchdog: pelo mesmo motivo do item 2, essas rotinas são usadas largamente e provavelmente serão usadas por um software rodando em loop também.

 

 

O jeito certo

 

Primeiro a biblioteca de watchdog deve ser desenvolvida de maneira a fornecer um watchdog de software a cada uma das diferentes tarefas do firmware (execução da main é uma tarefa, execução em interrupção de timer é outra tarefa, assim como execução em interrupção de ethernet, e etc.), então cada tarefa terá seu próprio watchdog simulado em software.

 

Para implementar a solução de diversos watchdogs em software, a biblioteca do watchdog fornece as seguintes funções:

 

Com essas três funções fica fácil usar o watchdog em diferentes tarefas. Na main, configura-se o timeout para o tempo suficiente (5 segundos, no caso) e chama-se apenas uma vez a função de refresh, que fica no início do loop infinito e, preferencialmente, logo antes da interface do usuário, pois um dos sintomas de um código congelado é a interface travada. Tendo o watchdog da main servido junto à interface garante que se a interface não rodar, o watchdog também não será servido e o sistema será reiniciado.

 

 

A main não deve usar a função wdClose, pois nunca para de executar. Ao contrário das demais tarefas que interrompem a execução, fazendo suas funções e depois se cessando, ou seja, rodam em interrupções. Para essas fica necessário usar a função wdClose logo antes da interrupção retornar, como mostra o snippet abaixo. No início da execução da interrupção wdOpen é usado para ativar o watchdog wdEthernet a um timeout de 1 segundo. Com isso, dentro de 1 segundo a função wdClose ou wdRefresh deve ser chamada para que o watchdog não dispare o sinal de reiniciar o sistema. No caso ilustrado o watchdog wdEthernet não é servido, apenas aberto e fechado.

 

 

Na verdade, apenas o watchdog virtual da função main seria o suficiente para garantir a eficácia da atuação do watchdog. Entretanto, frequentemente precisamos colocar timeouts na ordem de diversos segundos na main, e usando watchdogs distribuídos por tarefas atinge-se menor tempo de resposta na ocorrência de travamentos.

 

Quando se desenvolve uma biblioteca bem estruturada ela fica simples de usar, como os snippets mostram. Por trás dessas funções a biblioteca executa o seu algoritmo no seu próprio escopo eliminando complexidades das camadas superiores do software. Inserir esses níveis de abstração no código é sempre uma excelente prática de programação de sistemas embarcados.

 

Por fim, vimos que as funções wdOpen, wdRefresh e wdClose são usadas para controlar o watchdog simulado em software. Entretanto, o verdadeiro watchdog é um só, o de hardware, e que geralmente precisa ser servido a uma periodicidade na ordem de centenas de milésimos de segundos.

 

Para isso torna-se necessário usar uma função que verifica se algum dos watchdogs simulados em software extrapolou o tempo configurado e, por seguinte, sirva o watchdog de hardware. Essa função precisa garantir latência e deve ser chamada por uma interrupção de alta prioridade de timer. Abaixo o algoritmo da função.

 

 

Como eu havia prometido, abaixo segue o código completo da biblioteca. Sintam-se convidados para usá-la da maneira que lhes convir.

 

watchdog.h

 

 

watchdog.c

 

 

 

Conclusão

 

Neste post foi apresentado a maneira adequada de se utilizar watchdogs. Como muitas vezes pudemos descobrir, geralmente da pior maneira, que apenas o watchdog real, o de hardware, não é suficiente para que o sistema sempre seja reiniciado quando trancar e, assim, torna-se necessário uma solução criativa e efetiva como a apresentada.

 

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

[wpseo_breadcrumb]
Comentários:
Notificações
Notificar
guest
1 Comentário
recentes
antigos mais votados
Inline Feedbacks
View all comments
Tiago Possato
Tiago Possato
05/12/2014 10:31

Olá Felipe, essa sua biblioteca de Watchdog é ótima, está salvando meu projeto! Porém estou com algumas dúvidas em relação as funções “timeoutInit()” e “timeoutCheck_ms(…,…)”. Como não entendi a forma de implementá-las, fiz umas alterações e gostaria que você me desse sua opinião a respeito. Estou usando o TI-RTOS, da Texas em um placa Tiva C Connected Launchpad. A princípio está tudo funcionando, mas fiquei na dúvida se é ‘sorte’ ou a bliblioteca está trabalhando como a sua original. As alterações que fiz são essas: void wdOpen(enum eWdClient id, uint32_t timeoutMs) { switch (id) { case wdGlobal: gWdClientStatus.wdEnabled = 1;… Leia mais »

Talvez você goste:

Séries

Menu
Privacy Settings saved!
Configurações de Privacidade

Entenda quais dados e informações usamos para ter melhor entrega de conteúdo personalizado para você.

These cookies are necessary for the website to function and cannot be switched off in our systems.

Para usar este site, usamos os seguintes cookies tecnicamente exigidos

  • wordpress_test_cookie
  • wordpress_logged_in_
  • wordpress_sec

Decline all Services
Accept all Services