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: 1734
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:

iwanttolearn
Posts: 8
Joined: Thu Feb 25, 2021 7:57 am

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

Postby iwanttolearn » Wed Oct 30, 2024 2:20 pm

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?

MicroController
Posts: 1734
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 » Thu Oct 31, 2024 12:50 am

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.

iwanttolearn
Posts: 8
Joined: Thu Feb 25, 2021 7:57 am

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

Postby iwanttolearn » Thu Oct 31, 2024 9:53 pm

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:

egionet
Posts: 3
Joined: Thu Sep 26, 2024 4:34 am

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

Postby egionet » Thu Oct 31, 2024 10:02 pm

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

Who is online

Users browsing this forum: Bing [Bot] and 107 guests