The I2C bus is a maker’s best friend until you run out of unique addresses. If you need to connect four BME280 sensors (which all share address 0x76 or 0x77) to a single ESP32, you will hit a wall. The TCA9548A I2C multiplexer solves this by acting as a digital switchboard, splitting one main I2C bus into eight independent sub-buses. This primer covers the physical layer realities, protocol trade-offs, and the exact C++ code needed to get the TCA9548A (often sold as the Adafruit 2717 or generic clone boards) running reliably on your bench.

The Physical Layer: Wiring the TCA9548A I2C Multiplexer

Before writing a single line of code, you must respect the physical constraints of the I2C bus. The TCA9548A does not magically extend the physical limits of I2C; it merely isolates capacitance and address spaces. According to the NXP I2C-bus specification, the bus is strictly limited by wire capacitance (typically 400pF) and requires defined logic-high states.

Bus Mechanics and Specifications

Parameter Specification / Value Practical Constraint
Wires Required 4 (VCC, GND, SDA, SCL) Shared across main bus; sub-buses only need SDA/SCL/GND.
Bus Speed Standard (100kHz) / Fast (400kHz) TCA9548A supports both. Fast mode requires lower pull-up resistor values.
Base Address 0x70 Configurable to 0x77 via A0, A1, A2 pads on the breakout.
Max Distance ~1 meter (unbuffered) Longer runs require I2C bus extenders (e.g., P82B715) or twisted pair.
Capacitance Limit 400pF per sub-bus Multiplexer isolates sub-bus capacitance from the main bus.

The Pull-Up Resistor Rule

I2C lines are open-drain. This means devices can only pull the line LOW (to GND); they cannot drive it HIGH. The line is pulled HIGH by resistors connected to VCC. The TCA9548A IC itself does not contain internal pull-up resistors. If you are using a bare IC or a cheap clone breakout board lacking them, the bus will float, and your microcontroller will read garbage or hang.

Callout Tip: Sizing Your Pull-Ups
For a standard 100kHz bus with a few sensors, 4.7kΩ resistors from SDA and SCL to VCC (3.3V or 5V) are standard. If you push the bus to 400kHz (Fast Mode) or have long wires, the parasitic capacitance slows the rising edge of the signal. Drop the pull-ups to 2.2kΩ or even 1kΩ to charge the line faster. Refer to the TI TCA9548A Datasheet for exact rise-time calculations.

Protocol Selection: When I2C Multiplexing Beats SPI or UART

Makers often ask which protocol fits their distance, speed, and device count requirements. While I2C is convenient, multiplexing it adds complexity. Here is how the TCA9548A I2C multiplexer setup compares to SPI and UART when scaling up sensor networks.

Criteria I2C (via TCA9548A Mux) SPI (Hardware) UART (Hardware/Software)
Wire Count 2 shared + Mux VCC/GND 4 shared + 1 Chip Select per device 2 (TX/RX) per device pair
Max Speed 400 kHz (Fast Mode) 10 MHz to 50+ MHz 115200 bps (standard), up to 3 Mbps
Device Count Up to 100+ (8 sub-buses × devices) Limited by available GPIO for Chip Selects 1-to-1 (unless using RS-485 transceivers)
Max Distance < 1 meter (without buffers) < 1 meter (signal degrades fast) ~15 meters (via RS-485 differential)
Best Use Case Dozens of low-speed environmental sensors High-speed displays, SD cards, cameras GPS modules, long-distance telemetry

The Verdict: Choose the TCA9548A I2C multiplexer when you have a high device count of low-bandwidth sensors (like temperature, humidity, or light) clustered within a single enclosure. Choose SPI for high-throughput data, and UART/RS-485 when your sensors are spread across a room or vehicle.

Minimal Working Exchange: ESP32 and Arduino C++

The TCA9548A is controlled by writing a single byte to its address (0x70). Each bit in that byte corresponds to one of the 8 sub-buses (SD0 to SD7). Setting a bit to 1 enables that sub-bus; setting it to 0 disables it. You can enable multiple sub-buses simultaneously, provided the devices on them do not share addresses.

Physical Wiring to ESP32 DevKit V1

  • VCC: ESP32 3.3V pin to Mux VIN (Do not use 5V on standard ESP32 GPIOs without level shifting).
  • GND: ESP32 GND to Mux GND.
  • SDA: ESP32 GPIO 21 to Mux SD.
  • SCL: ESP32 GPIO 22 to Mux SC.
  • Sensors: Connect your target sensors to the SD0/SC0 through SD7/SC7 pads.

Complete C++ Code Example

This sketch initializes the bus, selects sub-bus 0, and performs a basic I2C scan. It includes error handling for the transmission state, which is critical for preventing silent bus lockups.

#include <Wire.h>

#define TCA_ADDRESS 0x70
#define MAIN_SDA 21
#define MAIN_SCL 22

// Helper function to switch TCA9548A sub-buses
void TCA9548A_Select(uint8_t bus) {
  Wire.beginTransmission(TCA_ADDRESS);
  // Write a byte where the nth bit is 1 to enable bus n
  Wire.write(1 << bus); 
  uint8_t error = Wire.endTransmission();
  
  if (error != 0) {
    Serial.print("TCA9548A Select Error on bus ");
    Serial.print(bus);
    Serial.print(". Wire.endTransmission returned: ");
    Serial.println(error);
    // Error 2 = NACK on address, Error 3 = NACK on data
  }
}

void setup() {
  Serial.begin(115200);
  Wire.begin(MAIN_SDA, MAIN_SCL);
  Serial.println("TCA9548A I2C Multiplexer Initialized.");

  // Select sub-bus 0
  TCA9548A_Select(0);
  
  // Example: Read from a sensor on bus 0
  // Wire.beginTransmission(SENSOR_ADDR);
  // ...
}

void loop() {
  // Cycle through buses 0 to 7 every 2 seconds
  for (uint8_t i = 0; i < 8; i++) {
    TCA9548A_Select(i);
    Serial.print("Scanning sub-bus ");
    Serial.println(i);
    
    for (uint8_t addr = 1; addr < 127; addr++) {
      Wire.beginTransmission(addr);
      if (Wire.endTransmission() == 0) {
        Serial.print("  Found device at 0x");
        Serial.println(addr, HEX);
      }
    }
    delay(2000);
  }
}

Sniffing the Bus and Classic Failure Modes

When the TCA9548A I2C multiplexer setup fails, it rarely fails silently. The bus will hang, your microcontroller will reset, or your sensors will return NaN (Not a Number). Here is how to diagnose the classic failures.

1. The Address Clash

Symptom: You enabled sub-bus 2 and sub-bus 3 simultaneously, and the bus locks up or returns corrupted data.
Cause: The TCA9548A electrically connects the enabled sub-buses in parallel. If you have a BME280 on bus 2 (address 0x76) and another BME280 on bus 3 (address 0x76), both will try to drive the SDA line low at the same time, causing a collision.
Fix: Only enable one sub-bus at a time if the devices share an address. Modify the TCA9548A_Select() function to clear all bits before setting the new one.

2. Missing or Incorrect Pull-Ups

Symptom: Wire.endTransmission() returns error code 2 (Address NACK) or the I2C scanner finds zero devices, even though wiring looks correct.
Cause: The SDA/SCL lines are floating. The microcontroller pulls them low, but nothing pulls them high, so the logic level never registers as a '1'.
Fix: Solder 4.7kΩ resistors between SDA and VCC, and SCL and VCC on the main bus. If using long wires to sub-buses, add 4.7kΩ pull-ups on the sub-bus side as well.

3. Baud Mismatch and Clock Stretching

Symptom: The ESP32 watchdog timer triggers a reset, or the sensor returns intermittent timeouts.
Cause: Some sensors (like certain SHT3x humidity modules) use "clock stretching"—they hold the SCL line LOW to force the master to wait while they process data. The TCA9548A passes this signal through, but if the sensor holds the line too long, the ESP32's I2C hardware peripheral times out.
Fix: Increase the I2C timeout in your microcontroller's Wire library settings, or lower the I2C clock speed to 50kHz to give the sensor more processing time per bit.

How to Sniff and Debug the I2C Bus

When serial printing isn't enough, you need to look at the physical signals. Use a logic analyzer (like a $15 Saleae Logic clone) connected to the main SDA and SCL lines. Set the sample rate to at least 4 MS/s (4x the 1MHz max I2C speed, though 400kHz is standard). Decode the I2C protocol in the software. Look specifically for the 9th clock pulse (the ACK bit). If the master sends an address and the SDA line stays HIGH on the 9th pulse, you have a NACK (No Acknowledge). This definitively proves the target device is not responding, pointing to a wiring fault, wrong address, or dead sensor.

TCA9548A I2C Multiplexer FAQ

Can I chain multiple TCA9548A multiplexers on the same main I2C bus?

Yes. The TCA9548A has three address pins (A0, A1, A2) on the IC. Most breakout boards expose these as solder pads. By bridging these pads to GND or VCC, you can change the multiplexer's I2C address from the default 0x70 up to 0x77. This allows you to chain up to eight multiplexers on a single main bus, giving you a theoretical maximum of 64 independent sub-buses.

Does the TCA9548A support 5V and 3.3V devices simultaneously?

No. The TCA9548A is a multiplexer, not a logic level shifter. The logic high voltage is dictated by the VCC pin. If you power the breakout with 5V, the sub-buses will output 5V logic, which will fry a 3.3V ESP32. If you power it with 3.3V, a strict 5V Arduino Uno might not recognize the 3.3V HIGH signal reliably. If you must mix voltages, place a dedicated BSS138-based I2C level shifter between the 5V sub-bus and the 3.3V microcontroller.

Why does my I2C bus lock up when I switch channels on the TCA9548A?

This usually happens if a sensor on a sub-bus was mid-transaction (holding SDA low) when the microcontroller reset or the channel was switched. When you switch back to that channel, the bus is stuck in a LOW state. To clear this "bus lockup," write a recovery routine in your setup() function that manually toggles the SCL pin as a standard GPIO output 9 times. This sends 9 dummy clock pulses, forcing the stuck sensor to release the SDA line and reset its internal state machine.