ESP32连续读取光度数据时Task Watchdog触发问题求助
ESP32 ESP-IDF 5.2 连续读取光度数据触发Task Watchdog问题解决建议
问题描述
基于ESP-IDF 5.2开发ESP32项目,需在连续循环中读取TSL2591光度数据,但始终触发Task Watchdog,提示IDLE0未及时复位。代码虽能继续运行,但实际执行时间远长于计时结果。延长看门狗超时至20秒仅临时有效,测量次数增至200000次时问题复现;添加10ms以上延迟可避免触发,但低于10ms会因默认tick周期导致无限循环。
错误日志
I (15255) MONIDAT: Measurement 86800: Luminosity: 3 I (15265) MONIDAT: Measurement 86900: Luminosity: 3 I (15285) MONIDAT: Measurement 87000: Luminosity: 3 I (15305) MONIDAT: Measurement 87100: Luminosity: 3 E (15305) task_wdt: Task watchdog got triggered. The following tasks/users did not reset the watchdog in time: E (15305) task_wdt: - IDLE0 (CPU 0) E (15305) task_wdt: Tasks currently running: E (15305) task_wdt: CPU 0: main E (15305) task_wdt: CPU 1: IDLE1 E (15305) task_wdt: Print CPU 0 (current core) backtrace Backtrace: 0x4200D673:0x3FC93300 0x4200DA90:0x3FC93320 0x40377175:0x3FC93350 0x4200AF31:0x3FC99090 0x4200B10C:0x3FC990C0 0x4200B1D3:0x3FC99100 0x4200BE12:0x3FC99130 0x42008436:0x3FC991D0 0x4200849B:0x3FC99200 0x420085E9:0x3FC99240 0x4201B877:0x3FC992A0 0x4037A9E1:0x3FC992D0 0x4200d673: task_wdt_timeout_handling at C:/ESP/components/esp_system/task_wdt/task_wdt.c:441 0x4200da90: task_wdt_isr at C:/ESP/components/esp_system/task_wdt/task_wdt.c:515 0x40377175: _xt_lowint1 at C:/ESP/components/xtensa/xtensa_vectors.S:1240 0x4200af31: s_i2c_send_commands at C:/ESP/components/driver/i2c/i2c_master.c:433 (discriminator 1) 0x4200b10c: s_i2c_transaction_start at C:/ESP/components/driver/i2c/i2c_master.c:509 0x4200b1d3: s_i2c_synchronous_transaction at C:/ESP/components/driver/i2c/i2c_master.c:780 0x4200be12: i2c_master_transmit_receive at C:/ESP/components/driver/i2c/i2c_master.c:995 0x42008436: tsl2591_read_register at C:/ESP/examples/get-started/lisi_monidat/main/lisi_monidat.c:34 0x4200849b: measure_task at C:/ESP/examples/get-started/lisi_monidat/main/lisi_monidat.c:55 0x420085e9: app_main at C:/ESP/examples/get-started/lisi_monidat/main/lisi_monidat.c:98 0x4201b877: main_task at C:/ESP/components/freertos/app_startup.c:208 0x4037a9e1: vPortTaskWrapper at C:/ESP/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:134 I (15375) MONIDAT: Measurement 87200: Luminosity: 3 I (15385) MONIDAT: Measurement 87300: Luminosity: 3 I (15405) MONIDAT: Measurement 87400: Luminosity: 3 I (15425) MONIDAT: Measurement 87500: Luminosity: 3
核心代码片段
void measure_task(i2c_master_dev_handle_t dev_handle) { uint8_t data[2]; int num_measurements = 100000; int64_t start_time = esp_timer_get_time(); for (int i = 0; i < num_measurements; i++) { ESP_ERROR_CHECK(tsl2591_read_register(TSL2591_REGISTER_CHAN0_LOW, data, 2,dev_handle)); uint16_t luminosity = (data[1] << 8) | data[0]; // Optionally log every 1000th measurement to avoid overwhelming the log if (i % 100 == 0) { ESP_LOGI(TAG, "Measurement %d: Luminosity: %d", i, luminosity); } } int64_t end_time = esp_timer_get_time(); float elapsed_time_sec = (end_time - start_time) / 1000000.0; ESP_LOGI(TAG, "Completed %d measurements in %.2f seconds good job", num_measurements, elapsed_time_sec); }
已尝试方案
- 创建tskIDLE_PRIORITY任务,无效
- 延长看门狗超时至20秒,仅临时解决,增加测量次数后复现
- 添加10ms以上延迟可避免触发,但低于10ms会导致无限循环
- 将任务绑定到核心1,无效
- 提高任务优先级,无效
解决方案建议
1. 主动让出CPU,给IDLE任务运行机会
Task Watchdog触发的核心原因是IDLE0任务长时间无法获得CPU时间复位看门狗。在循环中加入任务切换指令,让IDLE任务有执行窗口:
for (int i = 0; i < num_measurements; i++) { ESP_ERROR_CHECK(tsl2591_read_register(...)); // ... 光度数据处理 ... // 每N次读取后主动让出CPU if (i % 100 == 0) { taskYIELD(); // 无延迟切换,适合高频采样 // 或 vTaskDelay(0); 效果与taskYIELD()一致 } }
2. 配置I2C传输超时,避免无限阻塞
从backtrace看,I2C同步传输是阻塞式的,若总线异常会导致任务长时间占用CPU。初始化I2C时设置超时:
i2c_master_dev_config_t dev_cfg = { .dev_addr_length = I2C_ADDR_BIT_LEN_7, .device_address = TSL2591_ADDR, .scl_speed_hz = 400000, .timeout_ms = 100, // 设置传输超时时间 }; ESP_ERROR_CHECK(i2c_master_bus_add_device(i2c_bus_handle, &dev_cfg, &dev_handle));
3. 拆分长循环为批次处理
将大循环拆分为多个小批次,每批次执行完后让出CPU,平衡采样效率与系统稳定性:
void measure_task(i2c_master_dev_handle_t dev_handle) { uint8_t data[2]; int total_measurements = 200000; int batch_size = 1000; // 每批次处理1000次 int64_t start_time = esp_timer_get_time(); for (int i = 0; i < total_measurements; i++) { ESP_ERROR_CHECK(tsl2591_read_register(TSL2591_REGISTER_CHAN0_LOW, data, 2, dev_handle)); uint16_t luminosity = (data[1] << 8) | data[0]; if (i % 100 == 0) { ESP_LOGI(TAG, "Measurement %d: Luminosity: %d", i, luminosity); } // 每批次结束后让出CPU if ((i + 1) % batch_size == 0) { taskYIELD(); } } int64_t end_time = esp_timer_get_time(); float elapsed_time_sec = (end_time - start_time) / 1000000.0; ESP_LOGI(TAG, "Completed %d measurements in %.2f seconds", total_measurements, elapsed_time_sec); }
4. 调整TSL2591采样配置
通过传感器自身配置降低读取频率,减少CPU占用:
// 设置积分时间为100ms,低增益(根据实际场景调整) tsl2591_set_integration_time(dev_handle, TSL2591_INTEGRATIONTIME_100MS); tsl2591_set_gain(dev_handle, TSL2591_GAIN_LOW);
5. 临时禁用IDLE0看门狗(不推荐生产环境)
仅用于调试,禁用CPU0的IDLE任务看门狗监控:
task_wdt_config_t twdt_config = { .timeout_ms = 20000, .idle_core_mask = (1 << 1), // 仅监控CPU1的IDLE任务 .trigger_panic = false, }; task_wdt_init(&twdt_config);
内容的提问来源于stack exchange,提问作者Harith 75
相关产品推荐
相关产品推荐

