ESP32 I2C Repeated Start Condition with ESP-IDF Example

The lack of clear documentation on the ESP32 I2C repeated start condition (or I2C bus restart) programming is something that we have encountered often when developing low level firmware for our clients.

The ESP32 will need to generate a repeated start condition in many cases, especially when the I2C devices are sensors and the ESP32 needs to read data out of the sensor. In applications with audio codecs or sensors that have a complex register set, the I2C master must first send the register address and then read data out from that register instead of simply reading from the device using its call address and setting the direction bit to “read”.

Generating I2C repeated start in ESP-IDF code

Generating an ESP32 I2C repeated start or restart condition on the bus is easy. You simply need to add another start condition to the I2C command list. If there is another start condition after the first start condition, that is treated as a repeated start condition by the ESP-IDF I2C driver.

It is also important to leave the ACK check enabled on any byte transmission that happens just before the repeated start condition.

Example device that needs an I2C restart condition

There are several devices that will need a repeated start condition on the bus to read data from a specific I2C register address within the device. One such I2C device is the NXP SGTL5000 audio codec used in our AudioSOM32 module.

The SGTL5000 contains several registers inside and they are all 16-bit wide registers. To read the register content, the ESP32 must perform the following I2C operations:

  • Start condition
  • Send device address with the R/W bit = 0
  • Send two bytes for the 16 bit register address (MSB first)
  • Send repeated start condition (or a restart condition)
  • Send device address with the R/W bit = 1
  • Read two bytes from the addressed register (most significant byte first)
  • Stop condition
ESP32 I2C repeated start condition use example
Restart condition as required by SGTL5000, an I2C codec chip

ESP32 I2C repeated start code example

In the case above, the ESP32 needs to make an I2C restart condition to read register values from the SGTL5000. Lets see how that is actually implemented in ESP-IDF code. The code referenced here is from the sample code for AudioSOM32 audio codec driver (full code available on our GitHub repository).

esp_err_t as32_read_reg (i2c_port_t i2c_num, uint16_t reg_addr, uint16_t *reg_val)
{
    uint8_t *byte_val = reg_val;
    esp_err_t ret;

    i2c_cmd_handle_t cmd = i2c_cmd_link_create();

    // Start condition
    i2c_master_start(cmd);
    // Address + Write bit
    i2c_master_write_byte(cmd, (AS32I2C_ADDR<<1)|WRITE_BIT, ACK_CHECK_EN);
    // MSB for reg address
    i2c_master_write_byte(cmd, (reg_addr>>8)&0xFF, ACK_CHECK_EN);
    // LSB for reg address
    i2c_master_write_byte(cmd, (reg_addr&0xFF), ACK_CHECK_EN);

    // Restart (stop + start)
    i2c_master_start(cmd);

    // Address + read
    i2c_master_write_byte(cmd, (AS32_I2C_ADDR<<1)|READ_BIT, ACK_CHECK_EN);
    
    // MSB for reg data
    i2c_master_read(cmd, byte_val + 1, 1, ACK_VAL);
    // LSB for reg data
    i2c_master_read_byte(cmd, byte_val, NACK_VAL);
    
    i2c_master_stop(cmd);
    // Execute and return status, should return 0
    ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);
    return ret;
}

This is all you need to do to generate a repeated start or a restart condition that is expected by many I2C bus devices.

Change Log
  • Initial Release: 31 March 2021
References

You may also like

Leave a Comment

twenty + 20 =