No post anterior foi visto como configurar o clock do microcontrolador STM32F para rodar a 72 MHz, baseado no cristal externo.
Neste post serão explicados pra que são e como configurar os dois Watchdogs do STM32F (IWDG e WWDG).
O que é um Watchdog
O Watchdog (cão de guarda) é um periférico interno do microcontrolador que serve para identificar mal funcionamento do programa e reiniciar o sistema a partir de um reset.
É preciso recarregar/alimentar (reload/feed) periodicamente o Watchdog para que ele não cause um reset.
Então, quando um programa entra em um laço infinito ou entra em algum estado inconsistente que evita que o Watchdog seja adequadamente recarregado, o sistema vai resetar em um tempo máximo estipulado pela configuração do Watchdog.
IWDG – Independent Watchdog
O IWDG (Watchdog Independente) é chamado assim porque ele utiliza uma fonte de clock independente do clock do sistema.
Para habilitar o IWDG:
- Abra o arquivo IOC do projeto, entrar em “Pinout & Configuration > IWDG” e então habilitá-lo em “Activated”.
- O valor do prescaler (divisor de clock) e o valor de reload (recarregamento) podem ser configurados para se obter um tempo máximo de reset com precisão.
- Note que o clock usado pelo IWDG vem de um oscilador RC interno de 40 kHz, o que pode ser visto em “Clock Configuration”.
O IWDG pode ser recarregado a qualquer momento, independente do valor do seu contador. Ele vai causar um reset quando seu contador chegar até zero.
Com um clock de 40 kHz, prescaler igual a 16 e valor de recarregamento 4095, o IWDG causará um reset em de 1,6 segundos.
T = 16*(4095+1)/40000
Para evitar isso, chamamos a função que reseta o IWDG no fim do laço while(1){…}, o qual demora 1.0 segundo para ser executado:
int main(void) {
// ...
while (1)
{
// ...
// Recarrega o IWDG
HAL_IWDG_Refresh(&hiwdg);
// ...
}
// ...
}
Note que, para poder debugar o microcontrolador com o IWDG ativo, é necessário configurá-lo para que pare a contagem quando o processador pára em um breakpoint.
Na função MX_IWDG_Init() adicione as linhas a seguir:
static void MX_IWDG_Init(void)
{
// ...
// Necessário para parar o IWDG quando
// o programa para em um breakpoint
__HAL_DBGMCU_FREEZE_IWDG();
// ...
}
WWDG – Window Watchdog
O WWDG (Watchdog de Janela) é chamado assim porque com ele é possível configurar uma janela de tempo onde ele deve ser recarregado, de forma a não gerar um reset do microcontrolador. Se recarregar antes do tempo ou depois do tempo o reset ocorre.
Em outras palavras, o WWDG pode ser configurado para exigir um tempo mínimo e máximo entre os recarregamentos, causando um reset caso seja recarregado antes do tempo mínimo ou caso não seja recarregado no tempo máximo.
Este Watchdog funciona de forma um pouco diferente:
- Você configura um valor de recarregamento, por exemplo 127 (0x7F) a partir do qual o contador é decrementado. Se o valor do contador é reduzido a 63 (0x3F) ocorre o reset.
- Você também configura um valor de janela, o valor a partir do qual é permitido recarregar o WWDG. Se, quando recarregado, o contador é maior que este valor, o WWDG causa um reset. Se é menor ou igual, o WWDG é recarregado com sucesso, sem gerar um reset.
- Se você configurar este valor como sendo igual ao valor de recarregamento, o WWDG funciona como um Watchgod normal, sem o tempo mínimo.
- Você pode habilitar a interrução do WWDG, que ocorre quando o o valor do contador é reduzido a 64 (0x40).
Para habilitar o WWDG:
- Abra o arquivo IOC do projeto, entrar em “Pinout & Configuration > WWDG” e então habilitá-lo em “Activated”.
- Configure em “prescaler” o valor do divisor de clock.
- Configure em “window value” o valor da janela (início da janela).
- Configure em “down-counter” o valor do recarregamento (início da contagem).
- Habilite a interrupção do WWDG e, na aba “NVIC Settings” habilite a interrupção.
Com um clock de 72 MHz, portanto 36 MHz em APB1, prescaler igual a 8 e valor de recarregamento igual a 127, o WWDG causará um reset em de 58,2 milissegundos após o o recarregamento anterior.
T1 = 8*4096*(127-63)/36000000
Com o valor da janela igual a 64, a janela de recarregamento inicia em 57,3 milissegundos após o recarregamento anterior.
T2 = 8*4096*(127-64)/36000000
Dessa forma há uma janela de tempo de 0,091 milissegundos para que o recarregamento ocorra: depois de T2 e antes de T1.
ΔT = T1-T2 = 8*4096*(64-63)/36000000
+--------------------------+
| Recarrega Reset |
| |-------------|----| |
| T0 T2 T1 |
| <--> |
| Janela |
+--------------------------+
Para evitar isso, no arquivo main.c (ou em qualquer arquivo) criamos a função HAL_WWDG_EarlyWakeupCallback(), a qual chama a função de reset do WWDG.
Essa função criada é automaticamente chamada pelo tratamento da interrupção do WWDG.
void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg) {
// Recarrega o WWDG
HAL_WWDG_Refresh(hwwdg);
}
De forma semelhante ao IWDG, para que seja possível debugar o microcontrolador com o WWDG ativo, é necessário configurá-lo para que pare a contagem quando a execução é pausada em um breakpoint.
Na função MX_WWDG_Init() adicione as linhas a seguir:
static void MX_WWDG_Init(void)
{
// ...
// Necessário para parar o WWDG quando
// o programa para em um breakpoint
__HAL_DBGMCU_FREEZE_WWDG();
// ...
}
Por que dois Watchdogs?
Você pode se perguntar porque seriam necessários dois Watchdogs?
Caso o clock principal do sistema falhe, o que pode acontecer por exemplo escrevendo indevidamente em certos registradores, o WWDG vai parar de contar e, portanto, não causará reset. Nesse caso o IWDG entrará em ação, reiniciando o microcontrolador.
Além disso, como foi feito neste exemplo, ambos podem cuidar de dois escopos diferentes:
- IWDG pode ser recarregado a cada 1 segundo, garantindo que o laço de execução principal está sendo executado; e
- WWDG pode ser recarregado pela sua interrupção, garantindo que as interrupções não ficam desabilitadas por períodos muito longos.
Conclusão
Assim, com o uso de ambos os Watchdogs do STM32F, podemos obter uma garantia de que o programa está operando de forma correta: executando todas as suas tarefas e mantendo interrupções habilitadas.