解决esp32看门狗复位的问题
E (36942) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time: E (36951) task_wdt: - IDLE0 (CPU 0) E (36951) task_wdt: Tasks currently running: E (36951) task_wdt: CPU 0: WiFiTask E (36951) task_wdt: CPU 1: IDLE1 E (36951) task_wdt: Aborting. abort() was called at PC 0x4016113c on core 0
ELF file SHA256: 0000000000000000
Backtrace: 0x40094274:0x3ffbfd00 0x400944ed:0x3ffbfd20 0x4016113c:0x3ffbfd40 0x40090f2d:0x3ffbfd60 0x40085e05:0x3ffd2e60 0x400918e7:0x3ffd2e80 0x40091a46:0x3ffd2ea0 0x4017f20d:0x3ffd2ec0 0x400e4941:0x3ffd2ee0 0x400e16ec:0x3ffd2f00 0x400e1943:0x3ffd2f20 0x400e0b05:0x3ffd2f40 0x400e1086:0x3ffd2f90 0x400e12c5:0x3ffd3080 0x400d5746:0x3ffd3140 0x400d61e3:0x3ffd31e0 0x400954f2:0x3ffd3270
Rebooting...
在github上有个贴子也是讨论这个的,见https://github.com/espressif/arduino-esp32/issues/595
其中有一种解决办法是在循环中添加vTaskDelay(),即添加一个延时来供系统喂狗,但是这样会大大降低程序性能,freeRTOS中的延时基本都是微秒级别的,在我的程序中会降低程序采样率。在这个贴子中给出了很多方法,诸如自己构造一个很小的延时,关闭看门狗,在循环中喂狗等等,触发看门狗的原因下面有个老哥解释如下:
ESP-IDF creats a watchdog timer for idle tasks in addition to any tasks doing your work. IE, it creates two extra tasks IDLE0 & IDLE 1 (one for each core), whose sole purpose is to do nothing, ie idle. These idle tasks simply feed the watchdog whenever its respective core is idling. Whenever any task, in Arduino or in ESP-IDF, as well as interrupt routines, run with a higher priority than the IDLE tasks without delaying or blocking sufficiently long/often enough (such as when executing in a tight while loop), it triggers the watchdog, because that core is now fully busy, meaning it is no longer idling often enough, meaning the idle "tasks" get starved, so they can't reset the watchdog. Your app_main() in ESP-IDF and loop() in Arduino, run with higher priorities than the IDLE tasks. This is the source of the problem. You either have to make some call that blocks your code for atleast 10mS in sufficient intervals, or you have to call yield() or vTaskDelay(NUMBER_OF_MILLISECONDS_TO_DELAY / portTICK_PERIOD_MS) with a minimum of 10mS (otherwise, due to discreteness, it amounts to 0, ie no delay at all, thus won't work. You can work around this by increasing the scheduler frequency).
An alternative is fully disabling the watchdog, but this nullifies its uses. There is a more elegant solution. If you do need something to consume all available CPU time, and don't want to bother with considerations of delay or blocking, and don't want to disable the watchdog, but don't want it to bark, then put all intensive code operations in its own function or set of functions, and call it/each using the following task creation function:
xTaskCreate(someFunction, "HumanReadableNameofTask", 4096, NULL, tskIDLE_PRIORITY, NULL);
where your function has the following signature:
void someFunction(void* arg)
This won't trip the watchdog no matter what, because it uses the tskIDLE_PRIORITY priority. I'm not sure what value it has, but it seems greater than 10, because I tried 10 and it didn't work. Not sure if 11 did, which would be lower priority than the IDLE tasks. Note though, any code you place in someFunction(), won't execute at all except during times when the CPU is IDLE. So all your other code must still sleep/delay/block sufficiently enough to give it time to run. This is the ideal place for endless intensive code, such as motor control and PID control loops. But beware, tasks with identical priority can starve each other. So if you use more than one such function, each containing a tight loop, then I don't know whether one task can fully starve the other or not. Placing one at an even lower priority than the other won't help, it would only guarantee that that one gets starved, unless the one with higher priority blocks.
You can even do this in Arduino. Note: The loop() in Arduino is not intended for intensive calculations, which is why it not-so-smartly was placed at same priority as wifi. Whenever you do need to start intensive operations, start them on separate FreeRTOS tasks as mentioned above.
翻译过来大概就是:
ESP-IDF 为空闲任务创建了一个看门狗计时器,除了执行您工作的任何任务。IE,它创建了两个额外的任务 IDLE0 和 IDLE 1(每个内核一个),其唯一目的是什么都不做,即空闲。每当其各自的内核处于空闲状态时,这些空闲任务只是为看门狗提供服务。每当 Arduino 或 ESP-IDF 中的任何任务以及中断例程以比 IDLE 任务更高的优先级运行而没有延迟或阻塞足够长/经常足够长的时间(例如在紧密的 while 循环中执行时),它都会触发看门狗,因为该核心现在完全忙碌,这意味着它不再经常空闲,这意味着空闲的“任务”会被饿死,所以他们无法重置看门狗。ESP-IDF 中的 app_main() 和 Arduino 中的 loop() 以比 IDLE 任务更高的优先级运行。这就是问题的根源。
另一种方法是完全禁用看门狗,但这会使它的用途无效。有一个更优雅的解决方案。如果你确实需要一些东西来消耗所有可用的 CPU 时间,并且不想考虑延迟或阻塞,不想禁用看门狗,但又不想让它吠叫,那么把所有密集的代码在其自己的函数或函数集中进行操作,并使用以下任务创建函数调用它/每个:
xTaskCreate(someFunction, "HumanReadableNameofTask", 4096, NULL, tskIDLE_PRIORITY, NULL);
您的函数具有以下签名:
void someFunction(void* arg)
这无论如何都不会触发看门狗,因为它使用 tskIDLE_PRIORITY 优先级。我不确定它有什么价值,但它似乎大于 10,因为我尝试了 10 并且它不起作用。不确定 11 是否有,这将比 IDLE 任务的优先级低。但请注意,您放置在 someFunction() 中的任何代码都不会执行,除非在 CPU 空闲时。因此,您所有其他代码仍必须足够睡眠/延迟/阻塞以使其有时间运行。这是无休止的密集代码的理想场所,例如电机控制和 PID 控制循环。但请注意,具有相同优先级的任务可能会互相饿死。因此,如果您使用多个这样的函数,每个函数都包含一个紧密循环,那么我不知道一个任务是否会完全饿死另一个任务。将一个置于比另一个更低的优先级不会'
你甚至可以在 Arduino 中做到这一点。注意:Arduino 中的 loop() 不适用于密集计算,这就是为什么它不那么聪明地被置于与 wifi 相同的优先级的原因。每当您确实需要启动密集操作时,如上所述在单独的 FreeRTOS 任务上启动它们。
大概就是你的任务优先级比空闲任务高且你的任务在高密度的运行,所以导致系统的空闲函数无法执行喂狗从而导致看门狗触发,所以在建立任务时使用优先级tskIDLE_PRIORITY,根据后面老哥的解释他应该是0,反正是等效于空闲任务的优先级的,亲测看门狗不会被触发。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)