Page 1 of 1

Problems with I2C timeout

Posted: Sat Apr 01, 2023 10:11 pm
by Tropaion
Hello,

I'm pretty new to the IDF and I'm currently writing a i2c library for the sensor HTE501: https://www.epluse.com/fileadmin/data/p ... HTE501.pdf

The normal readings work without problem, but I have problems with the single shot measurement.
The sensor support two types to read the single shot measurement data (S.14):
* Single Shot Clock Stretching: In case a command with clock stretching enabled has been issued, the slave holds SCL low until the
calculation has been finished, time depends on resolution, max. ~19ms.
* Single Shot: A single-shot measurement is started after the command has been received successfully. The readout of
the calculated values RH and T is started by sending the I2C address again in read mode

I didn't manage to get it to work with clock stretching, always getting timeout error.
I also tried both with "i2c_master_write_read_device", but it still doesn't work.

The only version I have found working is when using a 20ms delay:

Code: Select all

esp_err_t hte501_measure(hte501_handle_t hte501, float* temp, float* hum)
{
    hte501_dev_t* pSensor = (hte501_dev_t*) hte501;

    // Receive buffer
    uint8_t buff[HTE501_SINGLE_SHOT_LENGTH];

    // Create command to send
    uint8_t cmd[] = {HTE501_SINGLE_SHOT_HIGH, HTE501_SINGLE_SHOT_LOW};

    // Send command
    esp_err_t err = i2c_master_write_to_device(pSensor->bus, pSensor->dev_addr, &cmd[0], 2, I2C_TIMEOUT);

    // Check for error
    ESP_LOGI(TAG, "%s", esp_err_to_name(err));
    if(err != ESP_OK) { return err; }

    vTaskDelay(20 / portTICK_PERIOD_MS);

    // Receive values
    err = i2c_master_read_from_device(pSensor->bus, pSensor->dev_addr, &buff[0], 6, I2C_TIMEOUT);

    // Check for error
    ESP_LOGI(TAG, "%s", esp_err_to_name(err));
    if(err != ESP_OK) { return err; }

    // Write serial number to log
    ESP_LOGI(TAG, "HTE501 Temp/Hum:");
    ESP_LOG_BUFFER_HEX(TAG, &buff[0], HTE501_SINGLE_SHOT_LENGTH);

    // Calculate temperature
    *temp = (float)(((uint16_t)buff[0] << 8) | buff[1]) / 100.0f;

    // Calculate humidity
    *hum = (float)(((uint16_t)buff[3] << 8) | buff[4]) / 100.0f;

    return err;
}
But it's a pretty unclean solution.
Does someone have a better idea? Maybe how to get it working with clock stretching?

Thanks for your help,
Tropaion

Re: Problems with I2C timeout

Posted: Mon Apr 03, 2023 10:10 pm
by MicroController
20ms of clock stretching seems to be quite a long time; might be more than the I2C peripheral can be configured to allow before detecting a timeout.

Seeing that the sensor has "status register 2" with flags to indicate when a new measurement can be read, I'd propose the following algorithm:
1. calculate the expected time your measurement should take
2. start the measurement
3. do something else, or just vTaskDelay, until the time from step 1 is (close to) elapsed
4. read "status register 2"; check if the measurement is done. If not, goto step 4.
5. read the measurement data.