espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.37k stars 7.21k forks source link

[TW#27859] esp-idf htu21d i2c timeout #2819

Closed PawWaw closed 5 years ago

PawWaw commented 5 years ago

I'm trying to write program on ESP32-PICO-D4 using htu21d, but I got some troubles with code. I'm using esp-idf.


int htu21d_init() {

    esp_err_t ret;

    // setup i2c controller
    i2c_config_t conf;
    conf.mode = I2C_MODE_MASTER;
    conf.sda_io_num = 18;
    conf.scl_io_num = 19;
    conf.sda_pullup_en = GPIO_PULLUP_DISABLE;
    conf.scl_pullup_en = GPIO_PULLUP_DISABLE;
    conf.master.clk_speed = 100000;
    ret = i2c_param_config(I2C_NUM_0, &conf);
    if(ret != ESP_OK) return HTU21D_ERR_CONFIG;

    // install the driver
    ret = i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0);
    if(ret != ESP_OK) return HTU21D_ERR_INSTALL;

    // verify if a sensor is present
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (HTU21D_ADDR << 1) | I2C_MASTER_WRITE, true);
    i2c_master_stop(cmd);
        ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_RATE_MS);
    if( ret == ESP_OK)
        ESP_LOGI(TAG, "OK");
        else
        ESP_LOGE(TAG, "I2C Timeout");

        cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (HTU21D_ADDR << 1) | I2C_MASTER_WRITE, true);
    i2c_master_write_byte(cmd, 0xF3, true);
    i2c_master_stop(cmd);
    ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);
    if( ret == ESP_OK)
        ESP_LOGI(TAG, "OK");
       else
        ESP_LOGE(TAG, "I2C Timeout");

    // wait for the sensor (50ms)
    vTaskDelay(50 / portTICK_RATE_MS);

    // receive the answer
    uint8_t msb, lsb, crc;
    cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (HTU21D_ADDR << 1) | I2C_MASTER_READ, true);
    i2c_master_read_byte(cmd, &msb, 0x00);
    i2c_master_read_byte(cmd, &lsb, 0x00);
    i2c_master_read_byte(cmd, &crc, 0x01);
    i2c_master_stop(cmd);
    ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);
    if( ret == ESP_OK)
        ESP_LOGI(TAG, "OK");
        else
        ESP_LOGI(TAG, "I2C Timeout");

    return HTU21D_ERR_OK;
}

Everything is okay (ret is ESP_OK), until program goes to "receive the answer" part. The "i2c_master_cmd_begin" returns "I2C Timeout". I tried everything I know and what I found in the Internet, but nothing works... Anyone know, what am I doing wrong?

koobest commented 5 years ago

Hi, @PawWaw Can you please try the receive the answer part as the follows?

    uint8_t raw[3] = {0};
    cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (HTU21D_ADDR << 1) | I2C_MASTER_READ, true);
    i2c_master_read(cmd, raw, 3, I2C_MASTER_LAST_NACK);
    i2c_master_stop(cmd);
    ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);

Can you provide a waveform of the communication? I think the I2C bus broken caused the timeout.

thanks!!

PawWaw commented 5 years ago

I don't know how to check the waveform :/ The problem didn't solve when I pasted your code.

koobest commented 5 years ago

OK, We will buy this sensor for testing.

PawWaw commented 5 years ago

Thank you very much. Close this thread?

koobest commented 5 years ago

You can keep it open, we will give you feedback here.

PawWaw commented 5 years ago

Don't buy this sensor. I'm afraid I'm just making some mistake somewhere in my code and because of that I get this timeout :(

koobest commented 5 years ago

Do you have an oscilloscope that can capture waveforms for communication?

PawWaw commented 5 years ago

No, I don't have.

koobest commented 5 years ago

May be I can use your code to do a test, but use a sensor I can find now.

koobest commented 5 years ago

Can you try to enable the GPIO internal pull?

conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
PawWaw commented 5 years ago

Sure, finally my code looks like that:

int htu21d_init() {

    esp_err_t ret;

    // setup i2c controller
    i2c_config_t conf;
    conf.mode = I2C_MODE_MASTER;
    conf.sda_io_num = 18;
    conf.scl_io_num = 19;
    conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
    conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
    conf.master.clk_speed = 100000;
    ret = i2c_param_config(I2C_NUM_0, &conf);
    if(ret != ESP_OK) return HTU21D_ERR_CONFIG;

    // install the driver
    ret = i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0);
    if(ret != ESP_OK) return HTU21D_ERR_INSTALL;

    // verify if a sensor is present
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (HTU21D_ADDR << 1) | I2C_MASTER_WRITE, true);
    i2c_master_stop(cmd);
    ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_RATE_MS);
    if( ret == ESP_OK)
        ESP_LOGI(TAG, "OK");
    else
        ESP_LOGE(TAG, "I2C Timeout");

    cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (HTU21D_ADDR << 1) | I2C_MASTER_WRITE, true);
    i2c_master_write_byte(cmd, 0xF3, true);
    i2c_master_stop(cmd);
    ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);
    if( ret == ESP_OK)
        ESP_LOGI(TAG, "OK");
    else
        ESP_LOGE(TAG, "I2C Timeout");

    // wait for the sensor (50ms)
    vTaskDelay(50 / portTICK_RATE_MS);

    // receive the answer
    uint8_t raw[3] = {0};
    cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (HTU21D_ADDR << 1) | I2C_MASTER_READ, true);
    i2c_master_read(cmd, raw, 3, I2C_MASTER_LAST_NACK);
    i2c_master_stop(cmd);
    ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);
    if( ret == ESP_OK)
        ESP_LOGI(TAG, "OK");
    else
        ESP_LOGE(TAG, "I2C Timeout");

    return HTU21D_ERR_OK;
}

` But it still gives "timeout" at receive the answer.

koobest commented 5 years ago

Just found that verify if a sensor is present may cause sensor status error, can you remove this part and take a try?

PawWaw commented 5 years ago

No difference, still in the receiving is timeout.

koobest commented 5 years ago

Ok, maybe this issue is caused by the sensor itself, and its timing is special. I will buy this sensor and try to support it.

koobest commented 5 years ago

Can you try to wait for more time when reading the sensor?

// wait for the sensor (100ms)
vTaskDelay(100 / portTICK_RATE_MS);
PawWaw commented 5 years ago

That was it... Thank you very much koobest, I would never think about it! przechwytywanie