I2C driver with multiplexer


I was curious if anyone had any advice regarding writing a driver for a series of sensors with an I2C multiplexer.

We want to use several hall-effect sensors, all of which have the same i2c address. To read from all of them on the same bus we use an I2C multiplexer which worked fine in our teensy test setup. We want to transition this to be read with a Px4 driver and published as a uORB message instead. I’ve written a single hall-effect sensor driver which works as expected, but am running into difficulties when trying to integrate the multiplexer.

The problem I am facing is that I would like to make a driver class for the multiplexer which contains the hall-effect driver class as a member, such that I can do something along the lines of

for (int i=0; i<3; ++i) {
    i2c::transfer() // write to multiplexer address (0x70) and select hall-effect i
    i2c::transfer() // read from hall-effect i2c address (0x35)
// use hall-effect data

but this seems difficult. Constructing a hall-effect object (TMAG5273) within the multiplexer class (PCA9546) means both will have the same BusInstanceIterator, which doesn’t feel correct. Not to mention the I2CSPIDriverConfig must be different for the two, at least for the address.

Given I only need to write a single byte to the multiplexer address (the index of the hall-effect), is there a simpler way to do this?

1 Like

Hi @mnissov,

we have also dealed with small number of I2C busses. Therefore ve have delopped TFI2CADT01 I2C address translator module.

The advantage of this access is that it does not requre any additional software/firmware. In only translates I2C device address by applaying XOR operation on orginal address. More informations about working of this translator is here: TFI2CADT01: I2C address translator | ThunderFly documentation page

With one piece of this TFI2CADT address translator you are able to connect 3 pieces of single-address sensor.

This seems doable with the hardware we have so not really looking to complicate the design anymore. Think the main limitation is my ability coding.

1 Like

As an update to the post:

Tried creating a class for handling specifically the I2C writing to the mux, as it’s only 1 byte which needs to be sent and no reading possible.

class PCA9546 : public device::I2C
  PCA9546(const I2CSPIDriverConfig& config)
    : I2C(DRV_MAG_DEVTYPE_PCA9546, "pca9546", config.bus, ADA_PCA9546::I2C_ADDRESS_DEFAULT, I2C_SPEED)

  bool select(uint8_t i)
    if (i >= NUMBER_OF_TMAG5273)
      PX4_ERR("select for index > NUMBER_OF_TMAG5273: %i", NUMBER_OF_TMAG5273);
      return false;

    this->transfer(&i, 1, nullptr, 0);
    return true;
  int probe() override
    return PX4_OK;

This is added to the total driver class as a member variable, where the idea is it should be sending a single byte with the index selector before attempting communication with a given sensor.

Reading a single sensor (no mux) works fine with this new class, as then the selector byte shouldn’t do anything. However coupled together with mux the probe on the sensor fails returning: PX4_qshell: no instance started (no device on bus?).

The same hardware works with teensy, so I assume this is a problem with sending to the mux in my px4 impl.

1 Like