最近我一直在折腾 ESP32 的多核功能,以及把任务固定到特定核心上。

我用 AutoConnect 来支持 WiFi 连接,这样就不用把凭据写死在代码里,还能通过网页界面进行 OTA 更新。

这是为一个项目准备的:控制我服务器机柜里的几个 CPU 4 针 PWM 风扇,给里面的空气降温。为此我想把逻辑拆成两个任务。

一个任务负责处理 API、传感器读取、更新、WiFi 等等,另一个任务负责中断和风扇的 PWM 控制。

一切都很顺利,任务也创建好了,但运行代码时,如果让 ESP32 进入需要你先连上它、再告诉它去连你的 WiFi 网络的那种模式,它就开始出现奇怪的行为:每隔几秒就重启一次控制器,我怎么都没法完成连接。

那段时间真是烦人,我不得不把控制器从原位拆下来,接上 USB 去刷新固件。

折腾完之后我注意到,错误来自看门狗:

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

四处查了查,看起来这是由 ESP32 的任务看门狗(Task Watchdog)触发的,它用来确保各个任务都能轮到 CPU 执行。

而且看起来,和直接跟其他所有代码、功能一起在任务之外运行相比,AutoConnect 在任务环境下运行时不太灵活。

我挖了挖,试了各种办法,发现摆脱这种局面最简单的方法,就是直接禁用看门狗,然后祈祷一切都能及时执行 🙂 这个任务并不是关键任务,所以多等一会儿让它把手头的事做完也无妨。

要禁用看门狗,你需要做两件事:

第一,引入 esp_task_wdt.h 头文件。为此,在你的 include 部分加上 #include <esp_task_wdt.h>

第二,让看门狗不再重置控制器,并且等待更长时间。为此,你需要在任务代码的开头加上 esp_task_wdt_init(30, false);。

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

这会把看门狗的超时时间设为 30 秒,并且在它被触发时不再重置控制器。

如果你希望看门狗触发后仍然重置控制器,把函数调用的第二个参数从 false 改成 true 即可。