Напоследък си играя с многоядрените възможности на 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.