Cascading/Daisy chain TCA9548

Hello guys,

I’m currently working on a project, and I need help connecting multiple (more than 8) TCA9548 devices together. Additionally, I need to be able to dynamically change the order of the connected TCA9548 modules.

I have:

  • Arduino UNO Wifi REV 2
  • TCA9548 1xI2C master - 8xI2C slave expander
  • EEPROM modul, AT24C256, I2C

I need to all TCA9548 devices to operate on a single address (default 0x70), and I am looking for a way to switch between them. Each TCA9548 has an EEPROM connected to it, containing a unique ID.

The connections are set up as follows:

  • The SDA and SCL lines from the Arduino are connected to the input pins (SDA and SCL) of TCA9548 #1.
  • The SD0 and SC0 (CH0) lines of TCA9548 #1 are connected to an EEPROM.
  • The SD1 and SC1 (CH1) lines of TCA9548 #1 are connected to the SDA and SCL inputs of TCA9548 #2.
  • On TCA9548 #2, the SD0 and SC0 (CH0) lines are again connected to another EEPROM.

In the following code, I attempted to first read the value from the EEPROM connected to TCA9548 #1 on SD0 and SC0 (CH0). Then, I switched to CH1 (SD1 and SC1) to read the value from the EEPROM connected to TCA9548 #2 on SD0 and SC0 (CH0). However, the value read from the EEPROM on TCA9548 #1 is the same as that from TCA9548 #2. I suspect that there might be some kind of looping occurring, or that the switch to TCA9548 #2 is not happening correctly, causing the value to always come from TCA9548 #1.

I am stuck and unsure how to resolve this. Have you encountered anyone dealing with a similar issue? Or do you know of any guides, articles, or videos that could help? Any advice would be greatly appreciated.

#include <Wire.h>

#define MUX_ADDRESS     0x70   // TCA9548 (both MUX #1 and MUX #2)
#define EEPROM_ADDRESS  0x50  

// -------------------------------------------------------------------------
// Helper function to check if a device responds (ACK) at MUX_ADDRESS.
bool isMuxPresent() {
  Wire.beginTransmission(MUX_ADDRESS);
  return (Wire.endTransmission() == 0);
}

// -------------------------------------------------------------------------
// Selects (opens) a specific channel 'channel' (0–7) on TCA9548.
// Returns true if endTransmission() returns 0 (success).
bool selectMuxChannel(uint8_t channel) {
  if (channel > 7) return false;
  Wire.beginTransmission(MUX_ADDRESS);
  Wire.write(1 << channel); 
  return (Wire.endTransmission() == 0);
}

// -------------------------------------------------------------------------
// Closes all channels on TCA9548 (i.e., sends 0x00).
bool disableAllMuxChannels() {
  Wire.beginTransmission(MUX_ADDRESS);
  Wire.write((uint8_t)0x00); 
  return (Wire.endTransmission() == 0);
}

// -------------------------------------------------------------------------
// Reads 3 bytes from EEPROM (0x50) starting from internal address 0x0000
// and stores them in `outBuf[0..2]`, appending '\0'.
// Returns true if 3 bytes were successfully read, otherwise false.
bool readEeprom3Bytes(char* outBuf) {
  // Move the EEPROM internal address pointer to 0x0000
  Wire.beginTransmission(EEPROM_ADDRESS);
  Wire.write((uint8_t)0x00); 
  Wire.write((uint8_t)0x00); 
  if (Wire.endTransmission() != 0) {
    return false; 
  }

  // Request 3 bytes
  uint8_t numBytes = 3;
  Wire.requestFrom((int)EEPROM_ADDRESS, (int)numBytes);
  if (Wire.available() < numBytes) {
    return false;
  }

  for (uint8_t i = 0; i < numBytes; i++) {
    outBuf[i] = Wire.read();
  }
  outBuf[numBytes] = '\0'; 

  return true;
}

// -------------------------------------------------------------------------
void setup() {
  Serial.begin(115200);
  Wire.begin();
  delay(1000);

  // Check if MUX #1 exists at address 0x70
  if (!isMuxPresent()) {
    Serial.println("MUX #1 (0x70) on the main bus is not responding. Exiting.");
    while (1) {} // End
  }
  Serial.println("Found MUX #1 (0x70).");

  // (A) OPEN CH0 on MUX #1 and read EEPROM
  if (!selectMuxChannel(0)) {
    Serial.println("Failed to open CH0 on MUX #1.");
    while (1) {}
  }
  delay(5);

  // Read 3 bytes from EEPROM #1
  char buffer1[4];
  if (readEeprom3Bytes(buffer1)) {
    Serial.print("Value from EEPROM on MUX #1 CH0: '");
    Serial.print(buffer1);
    Serial.println("'");
  } else {
    Serial.println("Error reading EEPROM on MUX #1 CH0.");
  }

  // (B) CLOSE ALL CHANNELS, WAIT 10s
  if (!disableAllMuxChannels()) {
    Serial.println("Failed to close all channels on MUX #1.");
  }
  Serial.println("All channels on MUX #1 are closed.");
  delay(2000);

  // (C) OPEN CH1 on MUX #1 (where MUX #2 is located)
  if (!selectMuxChannel(1)) {
    Serial.println("Failed to open CH1 on MUX #1.");
    while (1) {}
  }
  delay(5);

  // Check if MUX #2 responds with ACK at 0x70
  if (!isMuxPresent()) {
    Serial.println("MUX #2 (0x70) behind CH1 is not detected.");
    while (1) {}
  }
  Serial.println("Found MUX #2 (0x70) on CH1 of MUX #1.");

  // (D) Within MUX #2, select CH0 where EEPROM #2 is located
  if (!selectMuxChannel(0)) {
    Serial.println("Failed to open CH0 on MUX #2.");
    while (1) {}
  }
  delay(5);

  // Read 3 bytes from EEPROM #2
  char buffer2[4];
  if (readEeprom3Bytes(buffer2)) {
    Serial.print("Value from EEPROM on MUX #2 CH0: '");
    Serial.print(buffer2);
    Serial.println("'");
  } else {
    Serial.println("Error reading EEPROM on MUX #2 CH0.");
  }
}

void loop() {
}

Thanks. :))

8 x 8 would be 64 devices all with the same address so multiplexers would be needed.
Are you going to connect that many devices?

I am working on a system that should be able to collect data from bee hives. It should work based on a box that will contain a weight sensor, a temperature sensor and a microphone. Since beekeepers have multiple hives, I need to be able to dynamically add and change these boxes.
For example, if a beekeeper has 10 hives next to each other, I will need 10 boxes (one box per hive). One box will contain (TCA9548, EEPROM, weight sensor, temperature sensor, and microphone.) These boxes should be able to connect another box to each other. If a box gets damaged or stops working, I want to be able to replace it with another without having to change the internal wiring (this is why I can't use buses). All these boxes should be interconnected with each other using TCA9548 serial wiring. The first/master TCA9548 will be connected to the SDA and SLC lines on the Arduino.
Then Arduino will collect the data from all the TCA9548, save it as JSON and send it to the database. In theory this all works, the only thing I need to figure out is how to read the data with this type of wiring.

I don't think so.
The theory breaks down when you realize that if all TCAs have the same address, there is no way to discern which one is being accessed.
For example, you activate channel 1 of TCA #1 (0x70) to access TCA #2, this connects the I2C bus to TCA #2 (0x70 as well).
Now you access address 0x70.
Which of the devices responds? TCA #1, TCA #2, or both?
Now imagine the cascade...

There is another thing to consider

I2C-bus was developped for short distances on PCBs.
If you go beyond distances of 0,5m or at least 2m the I2C-bus will work unreliably.

A much higher reliable connection would be a simple serial interface.

You described that you want to record data from a varying number of hives.

Well the most characteristic thing about buses is to indeed have nothing to change in the internal wiring. You maybe referrering to I2C-adresses.

Distinguishing between between different members on the bus is made by member-IDs
send on the bus. The member ID could be set by using a small dip-switch or through the USB-interface and then storing the ID in the non-volatile memory of the microcontroller.

And as you could use 32bit number you can have 2^32 = 4.294.967.296 members.
Or if you use characters even more. Just depends on the protocol you develop.

I guess the bee hives where anywhere out in the field with no mains-power available
so the systems have to be battery-powered.
Will your system include a solar panel and a solar-charging system?
Or will you use pure batteries?

What size of the batteries will you use?
This will set limits on what technology to use for aquiring and storing the data.

For short distancies less than 20 m you could use wireless modules. This would have the advantage to put the boxes into a sleep-mode with much less power-consumption and to wake up the microcontroller in certain timeintervals or to wake up through an incoming wireless signal.

If you use a solar panel and a batterymanagement system of big enough size you don't have to care about power-consumption.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.