ESP32中portENTER_CRITICAL与vTaskSuspendAll使用问题及OTA更新故障
问题分析与解决方案
失败尝试的原因
- 尝试1:ESP-IDF对FreeRTOS的
taskENTER_CRITICAL宏做了修改,必须传入portMUX_TYPE类型的互斥量参数,无参调用不符合当前环境的宏定义。 - 尝试2:
taskENTER_CRITICAL会关闭CPU中断,而ESP_HTTPS_OTA是长时间操作,期间WiFi的中断无法处理,直接触发看门狗超时panic。 - 尝试3:
vTaskSuspendAll挂起了任务调度器,但ESP_HTTPS_OTA内部会调用带非0等待时间的队列操作,调度器挂起时这类操作会触发断言失败。
正确解决方案
因为OTA是长时间操作,不能用临界区(关中断)或挂起调度器的方式,应该针对性暂停自己的业务任务,保留WiFi相关系统任务运行:
方案1:直接暂停/恢复指定任务
- 提前保存需要暂停的3-4个业务任务的句柄(创建任务时保存
xTaskCreate返回的句柄,或用xTaskGetHandle("task_name")获取)。 - OTA执行前后分别暂停和恢复这些任务:
// 暂停业务任务 vTaskSuspend(task_handle_1); vTaskSuspend(task_handle_2); // ... 其他需要暂停的任务 // 执行OTA更新 esp_err_t rc = esp_https_ota(&config); // 恢复业务任务 vTaskResume(task_handle_1); vTaskResume(task_handle_2); // ... 其他任务
注意:不要暂停WiFi、TCP/IP相关的系统任务(如esp_wifi、tcpip_adapter等),否则会导致OTA失败。
方案2:用事件标志组让任务主动休眠(更优雅)
这种方式避免强制暂停任务,防止任务持有资源时被暂停导致死锁:
- 创建事件标志组:
#define OTA_IN_PROGRESS_BIT (1 << 0) #define OTA_COMPLETE_BIT (1 << 1) EventGroupHandle_t ota_event_group = xEventGroupCreate();
- 在业务任务的循环中检测事件,若OTA进行则休眠:
while(1) { // 检查OTA是否在进行,若在则等待完成 EventBits_t bits = xEventGroupWaitBits(ota_event_group, OTA_IN_PROGRESS_BIT | OTA_COMPLETE_BIT, pdFALSE, pdFALSE, portMAX_DELAY); if (bits & OTA_COMPLETE_BIT) { // OTA完成,清除标志,继续任务 xEventGroupClearBits(ota_event_group, OTA_COMPLETE_BIT); } // 正常业务逻辑 // ... }
- 执行OTA时设置/清除标志:
// 通知业务任务进入休眠 xEventGroupSetBits(ota_event_group, OTA_IN_PROGRESS_BIT); xEventGroupClearBits(ota_event_group, OTA_COMPLETE_BIT); // 执行OTA更新 esp_err_t rc = esp_https_ota(&config); // 通知业务任务恢复运行 xEventGroupSetBits(ota_event_group, OTA_COMPLETE_BIT); xEventGroupClearBits(ota_event_group, OTA_IN_PROGRESS_BIT);
内容的提问来源于stack exchange,提问作者monkey
相关产品推荐
相关产品推荐

