large delays between sequential i2c commands in esp-idf (bq27441)

adequatealbert
Posts: 2
Joined: Fri Jun 05, 2020 1:13 am

large delays between sequential i2c commands in esp-idf (bq27441)

Postby adequatealbert » Fri Jun 05, 2020 1:28 am

I am trying to write a driver for the BQ27441 Fuel Gauge in esp-idf.
This chip works fine on my hardware using the arduino library in an arduino project.
In my esp-idf driver i am encountering large delays between i2c transactions which is preventing the driver from working.

Since the code works in arduino, which is based on esp-idf, there is no problem with my hardware, and no problem with esp-idf itself.
So I would appreciate help with what I am doing wrong.

- ESP-IDF v4.2-dev-1660-g7d7521367-dirty
- ESP32-WROVER-B on custom PCB
- 10k pullups on I2C Bus

Screenshot from datasheet showing transaction I am trying to achieve
(Note I am aware the datasheet shows a sequential start for the read command rather than two transactions, I have tried it both ways with the same results but am doing it this way because this is how the arduino lib seems to do it)
Image
Output of my esp-idf code showing large delays
Image
Output of arduino code showing normal timing
Image

Code: Select all

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include <driver/i2c.h>

#define I2C_SCL_IO				22	//19               /*!< gpio number for I2C master clock */
#define I2C_SDA_IO				21	//18               /*!< gpio number for I2C master data  */
#define I2C_FREQ_HZ				100000           /*!< I2C master clock frequency */
#define I2C_PORT_NUM			I2C_NUM_1        /*!< I2C port number for master dev */
#define I2C_TX_BUF_DISABLE  	0                /*!< I2C master do not need buffer */
#define I2C_RX_BUF_DISABLE  	0                /*!< I2C master do not need buffer */
#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 BQ27441_I2C_ADDRESS 0x55

static const char* TAG = "I2C Test";

static esp_err_t i2c_master_init(void)
{
  i2c_config_t conf = {};
  conf.mode = I2C_MODE_MASTER;
  conf.sda_io_num = (gpio_num_t)I2C_SDA_IO;
  conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
  conf.scl_io_num = (gpio_num_t)I2C_SCL_IO;
  conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
  conf.master.clk_speed = I2C_FREQ_HZ;
  i2c_param_config(I2C_PORT_NUM, &conf);
  return i2c_driver_install(I2C_PORT_NUM, conf.mode, I2C_RX_BUF_DISABLE, I2C_TX_BUF_DISABLE, 0);
}

void i2cWriteTwoBytes(uint8_t subAddress, uint8_t byte0, uint8_t byte1)
{
  i2c_cmd_handle_t cmd = i2c_cmd_link_create();
  i2c_master_start(cmd);
  i2c_master_write_byte(cmd, (BQ27441_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, ACK_CHECK_EN);
  i2c_master_write_byte(cmd, subAddress, ACK_CHECK_EN);
  i2c_master_write_byte(cmd, byte0, ACK_CHECK_EN);
  i2c_master_write_byte(cmd, byte1, ACK_CHECK_EN);
  i2c_master_stop(cmd);
  esp_err_t ret = i2c_master_cmd_begin(I2C_PORT_NUM, cmd, 100 / portTICK_RATE_MS);
  i2c_cmd_link_delete(cmd);
}

// Write a single byte to
void i2cWriteByte(uint8_t byte)
{
  i2c_cmd_handle_t cmd = i2c_cmd_link_create();
  i2c_master_start(cmd);
  i2c_master_write_byte(cmd, (BQ27441_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, ACK_CHECK_EN);
  i2c_master_write_byte(cmd, byte, ACK_CHECK_EN);
  i2c_master_stop(cmd);
  esp_err_t ret = i2c_master_cmd_begin(I2C_PORT_NUM, cmd, 100 / portTICK_RATE_MS);
  i2c_cmd_link_delete(cmd);
}

// Read a specified number of bytes over I2C at a given subAddress
bool i2cReadBytes(uint8_t * dest, uint8_t count)
{
  i2c_cmd_handle_t cmd = i2c_cmd_link_create();
  i2c_master_start(cmd);
  i2c_master_write_byte(cmd, (BQ27441_I2C_ADDRESS << 1) | I2C_MASTER_READ, ACK_CHECK_EN);
  if (count > 1) {
    i2c_master_read(cmd, dest, count - 1, I2C_MASTER_ACK);
  }
  i2c_master_read_byte(cmd, dest + count - 1, I2C_MASTER_NACK);
  i2c_master_stop(cmd);

  esp_err_t ret = i2c_master_cmd_begin(I2C_PORT_NUM, cmd, 100 / portTICK_RATE_MS);
  i2c_cmd_link_delete(cmd);

  if(ret == ESP_OK)
    return true;
  else
    return false;
}

static void task_fuel_gauge(void *args)
{
  // Attempt to get the device type
  uint8_t devType[2];
  i2cWriteTwoBytes(0x00,0x01,0x00);
  i2cWriteByte(0x00);
  i2cReadBytes(devType,2);

  while(true)
  {
    vTaskDelay(500/portTICK_PERIOD_MS);
  }
}

void app_main(void)
{
  ESP_LOGI(TAG,"MAIN ENTRY");

  i2c_master_init();

  xTaskCreate(task_fuel_gauge, "fuel_gauge", 2048, (void* ) 0, 20, NULL);

}

adequatealbert
Posts: 2
Joined: Fri Jun 05, 2020 1:13 am

Re: large delays between sequential i2c commands in esp-idf (bq27441)

Postby adequatealbert » Sun Jun 07, 2020 12:08 am

SOLVED!

I manged to work this problem out.
The issue was that the I2C transactions were timing out due to clock stretching by the slave of 80us.

I fixed this by using:

Code: Select all

  i2c_set_timeout(I2C_PORT_NUM,0xFFFFF);
This sets the timeout to the highest value which is 12.5ms and allowed me to run the bq27441 at 10-400khz with no problems.

Who is online

Users browsing this forum: No registered users and 56 guests