如何让i2c_dev与直接使用i2c驱动的组件共存?
解决方案:ESP-LCD与TSL2591 I2C共存问题
问题根源
你当前使用了ESP-IDF v5.x及以上版本的新I2C主机总线API(i2c_new_master_bus),但TSL2591依赖的i2cdev组件是基于旧版I2C驱动API(i2c_driver_install)开发的。新旧API的总线上下文完全不兼容,i2cdev无法识别新API创建的总线句柄,导致内部信号量初始化失败,触发xQueueSemaphoreTake断言。
方案一:统一使用旧版I2C驱动API(推荐,无需修改组件)
将I2C总线初始化改为旧版API,同时为ESP-LCD适配旧版总线句柄,这样两个组件都能正常工作:
1. 修改I2C初始化代码
替换原有的i2c_new_master_bus调用,改用旧版驱动初始化:
void app_main(void) { esp_log_level_set("*", ESP_LOG_VERBOSE); ESP_LOGI(TAG, "Starting SSD1306 LCD application with LVGL..."); ESP_LOGI(TAG, "Initialize I2C bus (legacy API)"); // 旧版I2C初始化 i2c_config_t i2c_config = { .mode = I2C_MODE_MASTER, .sda_io_num = I2C_MASTER_SDA_IO, .scl_io_num = I2C_MASTER_SCL_IO, .sda_pullup_en = GPIO_PULLUP_ENABLE, .scl_pullup_en = GPIO_PULLUP_ENABLE, .master.clk_speed = 400000, // 400kHz }; ESP_ERROR_CHECK(i2c_param_config(I2C_NUM_0, &i2c_config)); ESP_ERROR_CHECK(i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0)); // 为ESP-LCD创建适配的总线句柄 esp_lcd_i2c_bus_handle_t lcd_i2c_bus = NULL; esp_lcd_i2c_bus_config_t lcd_i2c_config = { .i2c_port = I2C_NUM_0, .clk_speed = 400000, }; ESP_ERROR_CHECK(esp_lcd_new_i2c_bus(&lcd_i2c_config, &lcd_i2c_bus)); // 初始化组件 ESP_ERROR_CHECK(gpio_reset_init()); ESP_ERROR_CHECK(tsl2591_sensor_init()); ESP_ERROR_CHECK(lcd_init(lcd_i2c_bus)); // 传入适配后的LCD总线句柄 }
2. 确保TSL2591使用正确的I2C端口
在tsl2591_sensor_init中,配置i2c_dev_t时指定旧版的I2C端口:
esp_err_t tsl2591_sensor_init(void) { static i2c_dev_t dev; dev.port = I2C_NUM_0; // 和初始化的端口一致 dev.addr = TSL2591_ADDR; // 默认0x29 return tsl2591_init(&dev); }
方案二:修改TSL2591组件适配新版I2C主机API(进阶)
如果坚持使用新版I2C API,需要修改i2cdev组件或TSL2591的通信代码,让它使用i2c_master_bus_handle_t执行I2C操作:
1. 为TSL2591传入新版总线句柄
修改tsl2591_sensor_init,保存新版总线句柄:
static i2c_master_bus_handle_t g_i2c_bus; esp_err_t tsl2591_sensor_init(i2c_master_bus_handle_t i2c_bus) { g_i2c_bus = i2c_bus; // 后续直接用g_i2c_bus调用新版I2C API }
2. 替换TSL2591内部的I2C通信函数
将tsl2591.c中基于i2c_dev_t的读写函数,替换为新版API调用:
// 替换原有的i2c_dev_read_reg实现 static esp_err_t tsl2591_read_reg(uint8_t reg, uint8_t *data, size_t len) { static i2c_master_dev_handle_t dev_handle = NULL; if (dev_handle == NULL) { // 创建设备句柄(只需初始化一次) i2c_device_config_t dev_cfg = { .dev_addr_length = I2C_ADDR_BIT_LEN_7, .device_address = TSL2591_ADDR, .scl_speed_hz = 400000, }; ESP_ERROR_CHECK(i2c_master_bus_add_device(g_i2c_bus, &dev_cfg, &dev_handle)); } // 执行寄存器读操作 return i2c_master_transmit_receive(dev_handle, ®, 1, data, len, -1); }
关键注意事项
- 新旧I2C API不能混用:同一I2C端口只能用一种API初始化,否则会导致驱动冲突。
- 时钟速率保持一致:两个组件的I2C时钟速率要相同(比如都是400kHz),避免通信异常。
内容的提问来源于stack exchange,提问作者LambdaLantern
相关产品推荐
相关产品推荐

