One of the major limitations to I2C is the inherent address conflicts when you try to bus multiple sensors of the same type/family together. While all sensors have a default address, some give an option for a secondary, and fewer give tertiary addresses or beyond. Since most systems only have one I2C bus, you are limited in how many of those sensors are used.

The 9548 family of modules solves this problem: they are multiplexer.

The 9548A / 9548A Family

This family of modules from various manufacturers solves this problem quite cleanly. These modules are known as Multiplexers, or Muxers for short.

These are effectively electronic DPDT switches. Depending on what channel is selected, SDA and SCA are routed to SD0/SC0 through SD7/SC7.

A top view of the PCA9548A muxer board.

Selecting a channel

How these channels are selected is quite straight-forward: Each channel is a bit, whichever bit is a “1” is the one activated.

Bit 7
(MSB)
Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1Bit 0 (LSB)
Channel 000000001
Channel 100000010
Channel 200000100
Channel 300001000
Channel 400010000
Channel 500100000
Channel 601000000
Channel 710000000
Addressing the channels in a 9548 I2C multiplexer
void tcaselect(uint8_t i) {
  if (i > 7){
   return; // escapes invalid input
  }
 
  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission();  
}

Communicating with your sensor

The 9548 modules are fully transparent. As a result, communicating with your end sensors does not change!

All you do is call the select function with the channel number you are activating.

In the circuit below, a PCA9548A board is being used to interface six LSM6DSOX IMUs to a Mega2560.
Two IMUs are connected to channels 0, 1, and 2. On each of those channels, one IMU is default addressed 0x6A and the other has D0 pulled high for the secondary address of 0x6B.

  tcaselect(0);

    soxA.beginI2C(0x6A)
    soxB.beginI2C(0x6B)

  tcaselect(1);

    soxC.beginI2C(0x6A)
    soxD.beginI2C(0x6B)

  tcaselect(2);

    soxE.beginI2C(0x6A)
    soxF.beginI2C(0x6B)

...
...
...
...

  tcaselect(0);

    soxA.getEvent(&accelA, &gyroA, &tempA);
    soxB.getEvent(&accelB, &gyroB, &tempB);

  tcaselect(1);

    soxC.getEvent(&accelC, &gyroC, &tempC);
    soxD.getEvent(&accelD, &gyroD, &tempD);

  tcaselect(2);

    soxE.getEvent(&accelE, &gyroE, &tempE);
    soxF.getEvent(&accelF, &gyroF, &tempF);
A demo circuit using the PCA9548A to connect six sensors to a Mega2560.

Datasheet