Напоследък си играя с многоядрените възможности на ESP32 и закрепването на задачи към конкретни ядра.

Използвах AutoConnect, за да поддържам WiFi връзка без да съхранявам паролите в кода и да предоставя OTA ъпдейти през уеб интерфейса.

Това беше за проект, който щеше да управлява няколко 4-пинови CPU PWM вентилатора, които са в сървърния ми шкаф, за да охлаждат въздуха вътре. За целта исках да разделя логиката на две задачи.

Едната задача да се занимава с API-та, четене на сензори, ъпдейти, WiFi и т.н., а другата да обработва прекъсването и PWM управлението на вентилаторите.

Всичко беше наред, задачите бяха създадени, но когато пуснах кода и ESP32 влезеше в режима, в който трябва да се свържеш с него, за да му кажеш към коя WiFi мрежа да се свърже, започна да се държи странно – рестартираше контролера на всеки няколко секунди и не успявах да накарам връзката да работи.

Това беше досадно, защото трябваше да демонтирам контролера от мястото му и да го свържа по USB, за да кача нов фърмуер.

След като направих всичко това, забелязах, че грешката идва от 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

Поразрових се и излиза, че това се задейства от Task Watchdog-а на ESP32, който се грижи всички задачи да получават своя ред за изпълнение на процесора.

Изглежда също, че AutoConnect не е особено гъвкав, когато работи в контекста на задача, в сравнение с изпълнение извън такава, директно с всичкия останал код и функционалност.

След известно ровене и пробване на различни неща, излиза, че най-лесният начин да се измъкнеш от тази ситуация е просто да изключиш watchdog-а и да се надяваш нещата да се изпълнят навреме 🙂 Задачата не е критична, така че е нормално да се изчака повече, докато приключи с това, което прави.

За да изключите watchdog-а, трябва да направите две неща:

Първо, включете хедъра esp_task_wdt.h. За целта добавете #include <esp_task_wdt.h> към секцията с include-ите си.

Второ, накарайте watchdog-а да не рестартира контролера и да чака по-дълго. За целта трябва да добавите esp_task_wdt_init(30, false); в началото на кода на вашата задача.

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

Това ще зададе timeout на watchdog-а на 30 СЕКУНДИ и ще изключи рестартирането на контролера, ако се задейства.

Ако искате контролерът все пак да се рестартира след задействане на watchdog-а, сменете втория параметър на извикването на функцията от false на true.