Page 1 of 1

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

Posted: Fri Jan 05, 2024 10:28 pm
by raywo_esp
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?

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

Posted: Sat Jan 06, 2024 12:07 pm
by MicroController
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.

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

Posted: Sat Jan 06, 2024 9:26 pm
by raywo_esp
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:

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

Posted: Wed Oct 30, 2024 2:20 pm
by iwanttolearn
Hi! First of all, I think this new I2C driver really needs extra API for writing to an addressable register because copying the whole buffer every time you want to write something just doesn't make sense! And my question is, what about reading from a register? You need a repeated start after sending the register address. How can this be handled in the new driver?

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

Posted: Thu Oct 31, 2024 12:50 am
by MicroController
Yeah, I think the new I2C driver is... not quite as capable as it should be, to put it politely. Deprecating the previous driver while the new one is about 70% finished might have been a bit early.

As to the repeated start, i2c_master_transmit_receive() is probably what you're looking for.

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

Posted: Thu Oct 31, 2024 9:53 pm
by iwanttolearn
MicroController wrote: As to the repeated start, i2c_master_transmit_receive() is probably what you're looking for.
Oh that's correct. I totally missed that one :lol:

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

Posted: Thu Oct 31, 2024 10:02 pm
by egionet
Hi,

A bmp280 example using i2c_master.h is available here: https://github.com/K0I05/esp32-s3/tree/ ... 0_20240515

I am working on the bmp680 driver and hope to post it soon.

Available drivers are listed here: https://github.com/K0I05/esp32-s3/tree/ ... herals/i2c

Regards