Últimamente he estado jugando con la funcionalidad multinúcleo del ESP32 y con la asignación de tareas a núcleos específicos.

Estaba usando AutoConnect para permitir la conexión WiFi sin guardar las credenciales en el código y para ofrecer actualizaciones OTA desde la interfaz web.

Era para un proyecto que iba a controlar unos ventiladores PWM de CPU de 4 pines que tengo en el armario de mi servidor, para enfriar el aire de su interior. Para eso quería dividir la lógica en dos tareas.

Una tarea para manejar las APIs, la lectura de sensores, las actualizaciones, el WiFi, etc., y otra para manejar la interrupción y el control PWM de los ventiladores.

Todo iba bien, las tareas se crearon, pero al ejecutar el código, si ponía el ESP32 en el modo en el que hay que conectarse a él para indicarle que se conecte a tu red WiFi, empezaba a mostrar un comportamiento extraño: reiniciaba el controlador cada pocos segundos y no lograba que la conexión funcionara.

Fue un rato molesto, porque tuve que desmontar el controlador de su lugar y conectarlo por USB para cargarle un firmware nuevo.

Después de hacer eso noté que el error venía del 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

Investigando un poco, parece que esto lo dispara el Task Watchdog del ESP32, que se encarga de asegurar que las tareas tengan su turno de ejecución en la CPU.

Además, parecía que AutoConnect no era muy flexible al trabajar dentro del contexto de una tarea, en comparación con ejecutarlo fuera de una, directamente con el resto del código y la funcionalidad.

Después de buscar un poco y probar distintas cosas, parece que la forma más fácil de salir de esta situación es simplemente desactivar el watchdog y esperar que las cosas se ejecuten a tiempo 🙂 La tarea no es crítica, así que no pasa nada si tarda más en completar lo que está haciendo.

Para desactivar el watchdog, hay que hacer dos cosas:

Primero, incluir el encabezado esp_task_wdt.h. Para eso, agrega #include <esp_task_wdt.h> a tu sección de includes.

Segundo, hacer que el watchdog no reinicie el controlador y que espere más tiempo. Para ello, hay que añadir esp_task_wdt_init(30, false); al inicio del código de tu tarea.

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

Esto establecerá el tiempo de espera del watchdog en 30 SEGUNDOS y desactivará el reinicio del controlador si se dispara.

Si quieres que el controlador se reinicie de todos modos cuando se dispare el watchdog, cambia el segundo parámetro de la llamada a la función de false a true.