Estou projetando um firmware STM32 bare-metal que deve detectar código travado/perdido e reinicializar. Minha abordagem é fazer com que cada um dos processos de base de interrupção (basicamente código orientado a interrupção) incremente sua própria variável global conforme é executado, então em uma tarefa de 'supervisor' de prioridade mais alta, verifique para garantir que cada variável global esteja mudando. Se alguma parou de mudar, então permita que o WDT reinicie a placa.
Isso parece uma abordagem sólida? Alguma ideia melhor?
Assumindo uma arquitetura de "super-loop" de primeiro/segundo plano, com manipuladores de interrupção e um único thread principal, então eu sugeriria que um método melhor seria implementar tempos limite para cada interrupção.
Por exemplo, supondo que você implementou uma interface básica de tick do sistema (usando SYSTICK no Cortex-M), com uma função
tickms()
retornando o tempo decorrido em milissegundos. Então, para cada interrupção sendo watch-dogged, você pode ter uma enumeração como:Então uma matriz como:
e uma API:
Então, cada interrupção redefine seu tempo limite via
wdgReset()
, e o loop principal verifica continuamente os watchdogs de software, assim:Então:
wdgCheck()
irá girar e o watchdog de hardware irá disparar,wdgCheck()
,Observação: no Cortex-M, você pode emitir uma redefinição de software por meio do NVIC, portanto, você pode, opcionalmente, redefinir imediatamente quando o watchdog de software expirar, em vez de esperar pelo watchdog de hardware.
Claramente, este é apenas um esboço de pseudocódigo e puramente ilustrativo - ele poderia ser refinado e estendido de várias maneiras. Se você fosse usar um RTOS, você poderia proteger tarefas de forma semelhante, com o supervisor no loop ocioso ou em uma tarefa com prioridade menor do que qualquer outra.
Um refinamento que eu sugeriria seria ter um registro dinâmico de watchdogs de software em vez de uma matriz estática e ter uma API:
por exemplo, para que tarefas e drivers de dispositivo possam adicionar seus próprios watchdogs de forma independente, e
wdgCheck()
iterariam todos os manipuladores registrados. Uma tarefa poderia até mesmo modificar o período dinamicamente conforme necessário (se fosse temporariamente desabilitada, por exemplo):Primeiramente, observe que se nenhuma tarefa puder ser travada, o método mais simples é simplesmente configurar o watchdog timer de hardware adequadamente, já que uma reinicialização brusca do MCU é uma maneira aceitável de lidar com erros.
Você só precisa de supervisão de software nos seguintes casos:
Para simplificar, vamos supor que cada tarefa tenha permissão para consumir no máximo x ms, sem timeouts individuais. O pseudocódigo pode se parecer com isto:
Em alguns sistemas, você também poderá alternar entre os modos seguro e operacional e talvez reverter para o modo seguro em caso de erros.