Rewrite I2C read / write functions to use newer driver/i2c_master.h API

raywo_esp
Posts: 4
Joined: Wed Dec 27, 2023 1:34 pm

Rewrite I2C read / write functions to use newer driver/i2c_master.h API

Postby raywo_esp » Fri Jan 05, 2024 10:28 pm

I am currently trying to communicate with a BME680 sensor over I2C using the newest Bosch API and ESP IDF 5.3.

I found some very old code which seems to work but uses the API provided by driver/i2c.h. Since it is recommended to use the newer API driver/i2c_master.h I try to rewrite the code but having problems getting my head around it.

As per the BME-API one has to provide a write function for the used bus (which is I2C in my case). The signature is as follows:

Code: Select all

BME68X_INTF_RET_TYPE (*bme68x_write_fptr_t)(uint8_t reg_addr, const uint8_t *reg_data, uint32_t length, void *intf_ptr);
Where reg_addr is the 8bit register address of the sensor and reg_data is data to the specified address.

My old code is this:

Code: Select all

int i2c_slave_write(uint8_t bus, uint8_t addr, const uint8_t *reg,
                    uint8_t *data, uint32_t len) {

  i2c_cmd_handle_t cmd = i2c_cmd_link_create();
  i2c_master_start(cmd);
  i2c_master_write_byte(cmd, addr << 1 | I2C_MASTER_WRITE, true);
  if (reg)
    i2c_master_write_byte(cmd, *reg, true);
  if (data)
    i2c_master_write(cmd, data, len, true);
  i2c_master_stop(cmd);
  esp_err_t err = i2c_master_cmd_begin(bus, cmd, pdMS_TO_TICKS(1000));
  i2c_cmd_link_delete(cmd);

  return err;
}
So first the device address is written, then the register address and finally the data. After all is written the transaction is committed. At least that is how I understand the code.

How would I go about it with the new i2c_master.h API?
Currently I have something like this:

Code: Select all

BME68X_INTF_RET_TYPE BME680::write_i2c(uint8_t reg_addr,
                                       const uint8_t *reg_data,
                                       uint32_t length,
                                       void *intf_ptr) {
  assert(_instance->_device_handle);

  error = i2c_master_transmit(_instance->_device_handle,
                                        reg_data,
                                        length,
                                        -1);

  if (error != ESP_OK) {
    ESP_ERROR_CHECK_WITHOUT_ABORT(error);
    return -1;
  }

  return 0;
}
But there is the register address missing. How would I add it to the communication? Just doing another i2c_master_transmit with reg_addr doesn’t seem to do the trick.

Can anyone help?

MicroController
Posts: 1552
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: Rewrite I2C read / write functions to use newer driver/i2c_master.h API

Postby MicroController » Sat Jan 06, 2024 12:07 pm

Seems like you'll have to create a new uint8_t array, array[0] = reg_addr, copy the data to send to &(array[1]) and then transmit length+1 bytes from the new array.

raywo_esp
Posts: 4
Joined: Wed Dec 27, 2023 1:34 pm

Re: Rewrite I2C read / write functions to use newer driver/i2c_master.h API

Postby raywo_esp » Sat Jan 06, 2024 9:26 pm

Thanks @MicroController! This did the trick. :D

For reference, this is what it looks like now:

Code: Select all

reg_and_data[0] = reg_addr;
std::memcpy(&(reg_and_data[1]), reg_data, length);

esp_err_t error = i2c_master_transmit(_instance->_device_handle,
                                      reg_and_data,
                                      length + 1,
                                      -1);
As an old Java dude this C byte back and forth is a little bit tricky. :ugeek:

Who is online

Users browsing this forum: ShinyGlossy and 258 guests