You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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, &reg, 1, data, len, -1);
}

关键注意事项

  • 新旧I2C API不能混用:同一I2C端口只能用一种API初始化,否则会导致驱动冲突。
  • 时钟速率保持一致:两个组件的I2C时钟速率要相同(比如都是400kHz),避免通信异常。

内容的提问来源于stack exchange,提问作者LambdaLantern

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 10:44:52