Porting Arduino I2C method to ESP32?

Scalpel78
Posts: 51
Joined: Sun Feb 26, 2017 7:31 am

Porting Arduino I2C method to ESP32?

Postby Scalpel78 » Sun Apr 09, 2017 7:48 pm

Hi,
I'm working with a custom PCB that has a TCA9548 I2C multiplexer. From one of my previous boards were I used a Teensy and Arduino to control the TCA9548, I've used this method to change the channel:

Code: Select all

void setActiveSensor(uint8_t i)
{
  if (i > 7) return;

  Wire.beginTransmission(TCA_ADDRESS);
  Wire.write(1 << i);
  Wire.endTransmission();

  activeSensor = i;
}
Now, I'm trying to port this code over to ESP32. I've got I2C configured, and when I just query for the existence of the device I get a successful ACK back.

This is the code I'm using to replace the above Arduino code:

Code: Select all

esp_err_t tca9548_set_channel(int channel)
{
  //Contact the TCA9548. Does it respond with an ACK?
  i2c_cmd_handle_t cmd = i2c_cmd_link_create();
  ESP_ERROR_CHECK(i2c_master_start(cmd));
  ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (TCA_ADDRESS << 1)| I2C_MASTER_WRITE, ACK_CHECK_ON));
  //i2c_master_write_byte(cmd, (1 << channel) | I2C_MASTER_WRITE, 1 /* expect ack */);
  ESP_ERROR_CHECK(i2c_master_stop(cmd));

  //Send the I2C command
  esp_err_t result = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_PERIOD_MS);
  i2c_cmd_link_delete(cmd);

  if (result == ESP_OK)
  {
    printf("[OK] Found TCA9548!\n");
    //The TCA9548 responded
    uint8_t data[1];

    //Write to the register to set the active channel.
    cmd = i2c_cmd_link_create();
    ESP_ERROR_CHECK(i2c_master_start(cmd));
    ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (TCA_ADDRESS << 1) | I2C_MASTER_WRITE, ACK_CHECK_ON));
    ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (channel << 1), ACK));
    ESP_ERROR_CHECK(i2c_master_stop(cmd));
    result = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_PERIOD_MS);
    i2c_cmd_link_delete(cmd);

    return result;
  }
  else
  {
    //ESP_ERROR_CHECK(result);
    printf("[ERROR] [TCA9548] I2C ERROR: %d\n", result);
    return -1;
  }
}
I believe I can read data from the IC (at least it doesn't fail) using this code. This is for reading the same data that was written using the tca9548_set_channel(int) method.

Code: Select all

uint8_t tca9548_get_channel()
{
  //Contact the TCA9548. Does it respond with an ACK?
  i2c_cmd_handle_t cmd = i2c_cmd_link_create();
  ESP_ERROR_CHECK(i2c_master_start(cmd));
  ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (TCA_ADDRESS << 1)| I2C_MASTER_WRITE, ACK_CHECK_ON));
  //i2c_master_write_byte(cmd, (1 << channel) | I2C_MASTER_WRITE, 1 /* expect ack */);
  ESP_ERROR_CHECK(i2c_master_stop(cmd));

  //Send the I2C command
  esp_err_t result = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_PERIOD_MS);
  i2c_cmd_link_delete(cmd);

  if (result == ESP_OK)
  {
    uint8_t data[1];

    //Read the active channel from the IC
    cmd = i2c_cmd_link_create();
    ESP_ERROR_CHECK(i2c_master_start(cmd));
    ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (TCA_ADDRESS << 1) | I2C_MASTER_READ, ACK_CHECK_ON));
    ESP_ERROR_CHECK(i2c_master_read_byte(cmd, data, ACK));
    ESP_ERROR_CHECK(i2c_master_stop(cmd));
    ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_PERIOD_MS));
    i2c_cmd_link_delete(cmd);
    return data;
  }
  else
  {
    //ESP_ERROR_CHECK(result);
    printf("[ERROR] [TCA9548] I2C ERROR: %d\n", result);
    return -1;
  }
The problem is that the tca9548_get_channel() method always returns 0. So either the tca9548_set_channel() method isn't doing what it should, or the tca9548_get_channel isn't working properly, or both.

Can you see anything obvious I'm doing wrong here?

telanoc
Posts: 5
Joined: Fri Jan 13, 2017 1:02 am

Re: Porting Arduino I2C method to ESP32?

Postby telanoc » Mon Apr 10, 2017 12:05 am

I'm not familiar with the TCA9548, but don't you have to give the address of the register you're reading from? I know on the MCP23017 you do something like this:

Code: Select all

  // Specify register to read
   cmd = i2c_cmd_link_create();
   i2c_master_start(cmd);
   i2c_master_write_byte (cmd, (addr<<1) | I2C_MASTER_WRITE, ACK_CHECK_ON);
   i2c_master_write_byte (cmd, REG_GPIOA, ACK);
   i2c_master_cmd_begin (I2C_NUM_0, cmd, 100/ portTICK_PERIOD_MS);
   i2c_cmd_link_delete(cmd);
   
   // Now read a byte from that register
   cmd = i2c_cmd_link_create();
   i2c_master_start(cmd);
   i2c_master_write_byte (cmd, (addr<<1) | I2C_MASTER_READ, ACK_CHECK_ON);
   uint8_t res;
   i2c_master_read_byte (cmd, &res, ACK);
   i2c_master_cmd_begin (I2C_NUM_0, cmd, 100/ portTICK_PERIOD_MS);
   i2c_cmd_link_delete(cmd);
   
   return res;

Scalpel78
Posts: 51
Joined: Sun Feb 26, 2017 7:31 am

Re: Porting Arduino I2C method to ESP32?

Postby Scalpel78 » Mon Apr 10, 2017 9:17 am

Hi telanoc, thanks for your reply.

Yes, in most cases you have to specify which register you want to read from, but for devices that only have one register you don't need to specify which one you want. In the TCA9548 datasheet, in section 8.5.3, this is described as a single-register device.

From the datasheet:
Some devices are simple and contain only 1 register, which may be written to directly by sending the register data immediately
after the slave address, instead of addressing a register. The TCA9548A is example of a single-register device, which is controlled via I2C commands. Since it has 1 bit to enable or disable a channel, there is only 1 register needed, and the master merely writes the register data after the slave address, skipping the register number.


Note also that the Arduino code I'm porting from works.

Who is online

Users browsing this forum: Google [Bot] and 89 guests