4
\$\begingroup\$

I am trying to read a temperature and humidity sensor (SI7020) using I2C on the ESP32.

I modified their example code to read just from one slave device (0x40) but some commands do not work. I tried resetting the device with 0xFE as well.

I can read the device ID (0xFA):

*******************
TASK[0]  MASTER READ SENSOR( SI7020 )
*******************
data_h: 48
data_l: 52
sensor val: 15428.333333

reading device ID

However if I try and read the temperature (0xE3), I get:

data_h: 00
data_l: 00

enter image description here

If I use 0xE0 I always get:

data_h: 39
data_l: 9f

Why am I not able to read the temperature from SI7020?

The code I'm using:

#include <stdio.h>
#include "driver/i2c.h"


#define DATA_LENGTH          512  /*!<Data buffer length for test buffer*/
#define RW_TEST_LENGTH       127  /*!<Data length for r/w test, any value from 0-DATA_LENGTH*/
#define DELAY_TIME_BETWEEN_ITEMS_MS   2000 /*!< delay time between different test items */

#define I2C_EXAMPLE_MASTER_SCL_IO    19    /*!< gpio number for I2C master clock */
#define I2C_EXAMPLE_MASTER_SDA_IO    18    /*!< gpio number for I2C master data  */
#define I2C_EXAMPLE_MASTER_NUM I2C_NUM_1   /*!< I2C port number for master dev */
#define I2C_EXAMPLE_MASTER_TX_BUF_DISABLE   0   /*!< I2C master do not need buffer */
#define I2C_EXAMPLE_MASTER_RX_BUF_DISABLE   0   /*!< I2C master do not need buffer */
#define I2C_EXAMPLE_MASTER_FREQ_HZ    100000     /*!< I2C master clock frequency */

#define SI7020_SENSOR_ADDR  0x40    /*!< slave address for SI7020 sensor */
#define SI7020_CMD_READ    0xE0    /*!< Command to set measure mode */
//#define ESP_SLAVE_ADDR 0x28         /*!< ESP32 slave address, you can set any 7bit value */
#define WRITE_BIT  I2C_MASTER_WRITE /*!< I2C master write */
#define READ_BIT   I2C_MASTER_READ  /*!< I2C master read */
#define ACK_CHECK_EN   0x1     /*!< I2C master will check ack from slave*/
#define ACK_CHECK_DIS  0x0     /*!< I2C master will not check ack from slave */
#define ACK_VAL    0x0         /*!< I2C ack value */
#define NACK_VAL   0x1         /*!< I2C nack value */

xSemaphoreHandle print_mux;

/**
 * @brief test code to write esp-i2c-slave
 *
 * 1. set mode
 * _________________________________________________________________
 * | start | slave_addr + wr_bit + ack | write 1 byte + ack  | stop |
 * --------|---------------------------|---------------------|------|
 * 2. wait more than 24 ms
 * 3. read data
 * ______________________________________________________________________________________
 * | start | slave_addr + rd_bit + ack | read 1 byte + ack  | read 1 byte + nack | stop |
 * --------|---------------------------|--------------------|--------------------|------|
 */
static esp_err_t i2c_example_master_sensor_test(i2c_port_t i2c_num, uint8_t* data_h, uint8_t* data_l)
{
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, SI7020_SENSOR_ADDR << 1 | WRITE_BIT, ACK_CHECK_DIS);
    i2c_master_write_byte(cmd, SI7020_CMD_READ, ACK_CHECK_EN);
    i2c_master_stop(cmd);
    int ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);
    if (ret == ESP_FAIL) {
        return ret;
    }
    vTaskDelay(1000 / portTICK_RATE_MS);

    cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, SI7020_SENSOR_ADDR << 1 | READ_BIT, ACK_CHECK_DIS);
    i2c_master_read_byte(cmd, data_h, ACK_VAL);
    i2c_master_read_byte(cmd, data_l, NACK_VAL);
    i2c_master_stop(cmd);
    ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);
    if (ret == ESP_FAIL) {
        return ESP_FAIL;
    }
    return ESP_OK;
}

/**
 * @brief i2c master initialization
 */
static void i2c_example_master_init()
{
    int i2c_master_port = I2C_EXAMPLE_MASTER_NUM;
    i2c_config_t conf;
    conf.mode = I2C_MODE_MASTER;
    conf.sda_io_num = I2C_EXAMPLE_MASTER_SDA_IO;
    conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
    conf.scl_io_num = I2C_EXAMPLE_MASTER_SCL_IO;
    conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
    conf.master.clk_speed = I2C_EXAMPLE_MASTER_FREQ_HZ;
    i2c_param_config(i2c_master_port, &conf);
    i2c_driver_install(i2c_master_port, conf.mode,
                       I2C_EXAMPLE_MASTER_RX_BUF_DISABLE,
                       I2C_EXAMPLE_MASTER_TX_BUF_DISABLE, 0);
}

static void i2c_test_task(void* arg)
{
    int i = 0;
    int ret;
    uint32_t task_idx = (uint32_t) arg;
    uint8_t* data = (uint8_t*) malloc(DATA_LENGTH);
    uint8_t sensor_data_h, sensor_data_l;

    while (1) {
        ret = i2c_example_master_sensor_test( I2C_EXAMPLE_MASTER_NUM, &sensor_data_h, &sensor_data_l);
        xSemaphoreTake(print_mux, portMAX_DELAY);
        printf("*******************\n");
        printf("TASK[%d]  MASTER READ SENSOR( SI7020 )\n", task_idx);
        printf("*******************\n");
        if (ret == ESP_OK) {
            printf("data_h: %02x\n", sensor_data_h);
            printf("data_l: %02x\n", sensor_data_l);
            printf("sensor val: %f\n", ( sensor_data_h << 8 | sensor_data_l ) / 1.2);
        } else {
            printf("No ack, sensor not connected...skip...\n");
        }
        xSemaphoreGive(print_mux);
        vTaskDelay(( DELAY_TIME_BETWEEN_ITEMS_MS * ( task_idx + 1 ) ) / portTICK_RATE_MS);

        //---------------------------------------------------
        for (i = 0; i < DATA_LENGTH; i++) {
            data[i] = i;
        }
    }
}

void app_main()
{
    print_mux = xSemaphoreCreateMutex();
    //i2c_example_slave_init();
    i2c_example_master_init();

    xTaskCreate(i2c_test_task, "i2c_test_task_0", 1024 * 2, (void* ) 0, 10, NULL);
    //xTaskCreate(i2c_test_task, "i2c_test_task_1", 1024 * 2, (void* ) 1, 10, NULL);
}
\$\endgroup\$
3
  • \$\begingroup\$ Which mode did you try hold master mode or no hold master mode? I do not know if it is really related but for me with ESP8266 and SI7021 only no hold master mode worked. Hold Master Mode only avaliable for hum and temp readings so maybe that is why other commads work for you. \$\endgroup\$ Oct 6, 2017 at 20:44
  • 1
    \$\begingroup\$ So command E0 will won't work alone as it will return a temperature value measured during the previous humidity measurement. So before E0 you will always need to use E5 or F5 commands first. With E3 you are using the Hold Master Mode, I2C clock streching and possbily ESP or your code cannot handle that. Use the F3 command, with that Si7020 won't do clock streching. To get the result you have to wait like 9-10 ms after sending the F3 and then you should issue an I2C read operation to get the temp value. \$\endgroup\$ Oct 6, 2017 at 20:55
  • \$\begingroup\$ @Bence Kaulics F3 is giving me the same response as E3 in my original post. And even after issuing E5 and F5, E0 gives the same response as before. Lines 43-69 I believe are consistent with sequence shown in the SI7020 datasheet. \$\endgroup\$
    – physiii
    Oct 7, 2017 at 12:40

1 Answer 1

2
\$\begingroup\$

Your oscillogram shows an isolated read transaction, while the datasheet shows a write transaction prefixing a restart and the read transaction. I have already see some buggy I2C devices that only implement a subset of the possible I2C transactions, could be the case for this one. I suggest to try a transaction that look exactly as the datasheet show.

As I understand, you should use the 0xF3 command multiple times instead of a single 0xE0.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.