Recentemente andei brincando com a funcionalidade multicore do ESP32 e com a fixação de tarefas em núcleos específicos.

Eu estava usando o AutoConnect para dar suporte à conexão WiFi sem guardar credenciais no código e para oferecer atualizações OTA pela interface web.

Era para um projeto que ia controlar alguns coolers de CPU de 4 pinos com PWM que ficam no meu armário de servidores, para resfriar o ar lá dentro. Para isso, eu queria dividir a lógica em duas tarefas.

Uma tarefa para cuidar das APIs, leitura de sensores, atualizações, WiFi etc., e outra para cuidar da interrupção e do controle PWM dos ventiladores.

Tudo certo, as tarefas foram criadas, mas ao rodar o código, se eu colocava o ESP32 no modo em que você precisa se conectar a ele para dizer a qual rede WiFi ele deve se conectar, ele começava a ter um comportamento estranho: resetava o controlador a cada poucos segundos e eu não conseguia fazer a conexão funcionar.

Foi um momento chato, ter que desmontar o controlador do lugar dele e ligar no USB para gravar um firmware novo.

Depois de fazer isso, percebi que o erro vinha do watchdog:

Task watchdog got triggered. The following tasks did not feed the watchdog in time:

IDLE (CPU 1)
Tasks currently running:
CPU 0: ManageTask
CPU 1: ControllerTask

Pesquisando, parece que isso é disparado pelo Task Watchdog do ESP32, que garante que as tarefas tenham a sua vez de executar na CPU.

E também parecia que o AutoConnect não era muito flexível quando rodava dentro de uma tarefa, em comparação a rodar fora de uma, direto com todo o resto do código e das funcionalidades.

Fuçando um pouco e tentando coisas diferentes, parece que a forma mais fácil de sair dessa situação é simplesmente desabilitar o watchdog e torcer para que as coisas sejam executadas a tempo 🙂 A tarefa não é crítica, então tudo bem esperar mais tempo para ela terminar o que está fazendo.

Para desabilitar o watchdog, você precisa fazer duas coisas:

Primeiro, incluir o header esp_task_wdt.h. Para isso, adicione #include <esp_task_wdt.h> na sua seção de includes.

Segundo, fazer o watchdog não resetar o controlador e esperar mais tempo. Para isso, você precisa adicionar esp_task_wdt_init(30, false); no início do código da sua Task.

void manage_core_task(void *pv_parameters) {
    esp_task_wdt_init(30, false);
    // .... rest of the code ...
}

Isso vai definir o timeout do watchdog para 30 SEGUNDOS e desabilitar o reset do controlador caso ele seja disparado.

Se você quiser que o controlador ainda seja resetado depois que o watchdog disparar, mude o segundo parâmetro da chamada da função de false para true.