Documentation

TCA9548A 1-to-8 I2C 8-Channel Multiplexer Module | ShillehTek Product Manual
Documentation / TCA9548A 1-to-8 I2C 8-Channel Multiplexer Module | ShillehTek Product Manual

TCA9548A 1-to-8 I2C 8-Channel Multiplexer Module | ShillehTek Product Manual

cjmcu-9548-tca9548a-1-to-8-i2c-8-channel-multiplexer-moduleESP32I2CmanualMultiplexershillehtekTCA9548A

Overview

The TCA9548A is an 8-channel bidirectional I2C switch from Texas Instruments that lets a single microcontroller talk to up to 8 I2C devices that share the same address. If you have ever tried to wire two BME280 sensors to the same bus and watched them collide at 0x76, this is the chip that solves that problem cleanly without bit-banging a second software I2C bus.

The way it works is simple. The master MCU connects to the upstream SDA/SCL pins and addresses the TCA9548A itself at 0x70 (default). You write a single control byte where each bit enables one of the 8 downstream channels (SD0/SC0 through SD7/SC7). Whichever channels you enable get electrically connected to the upstream bus, and the others are isolated. Read your sensor, switch channels, read the next sensor, and so on.

Beyond duplicate-address fanout, the TCA9548A is also handy for mixed-voltage I2C (each child channel is independently level-translated against VCC), for isolating noisy devices from clean sensors, and for building hot-swappable I2C trees. The three address pins A0/A1/A2 let you put up to 8 muxes on the same parent bus, giving you a theoretical 64 child channels from a single MCU. That is a lot of BME280s.

At a Glance

Chip
TI TCA9548A
Channels
8 bidirectional I2C
Default Address
0x70 (0x70–0x77)
Voltage
1.65V – 5.5V
Max Clock
400 kHz Fast Mode
Best For
Duplicate-address I2C devices

Specifications

Parameter Value
IC Texas Instruments TCA9548A
Operating Voltage 1.65V to 5.5V (3.3V and 5V logic friendly)
Number of Channels 8 (SD0/SC0 to SD7/SC7)
I2C Address 0x70 default, A0/A1/A2 set 0x70–0x77
Maximum SCL Frequency 400 kHz
Supply Current (Operating) ~80 µA typical
Standby Current ~1 µA
Channel On-Resistance ~4 Ω typical
Reset Pin Active-low, internal pull-up
Mux-per-Bus Limit Up to 8 (via A0/A1/A2)
Operating Temperature -40°C to +85°C
Package on Module TSSOP-24 on breakout PCB

Pinout Diagram

TCA9548A 1-to-8 I2C multiplexer pinout showing VIN, GND, SDA, SCL master pins and 8 channels SD0/SC0 through SD7/SC7 plus address select A0/A1/A2 and RESET.

Wiring Guide

Arduino Uno / Nano (5V logic):

  • TCA9548A VIN → Arduino 5V
  • TCA9548A GND → Arduino GND
  • TCA9548A SDA → Arduino A4 (SDA)
  • TCA9548A SCL → Arduino A5 (SCL)
  • TCA9548A RESET → leave floating or tie to 5V
  • A0/A1/A2 → tie to GND for default 0x70
  • Wire each child sensor to SDn/SCn (channel 0–7) plus VIN and GND

Most I2C sensor breakouts already have 4.7k pull-ups, so you usually do not need to add more. If you see flaky reads on long wires, add 4.7k pull-ups to 3.3V or 5V on each child channel.

ESP32 DevKit (3.3V logic):

  • TCA9548A VIN → ESP32 3.3V
  • TCA9548A GND → ESP32 GND
  • TCA9548A SDA → GPIO21 (default SDA)
  • TCA9548A SCL → GPIO22 (default SCL)
  • RESET → floating, or tie to a GPIO for software reset
  • A0/A1/A2 → GND for address 0x70

ESP32 has internal pull-ups but they are weak. The TCA9548A breakout usually has them on the master side already.

Raspberry Pi (3.3V logic):

  • TCA9548A VIN → Pi 3.3V (pin 1)
  • TCA9548A GND → Pi GND (pin 6)
  • TCA9548A SDA → Pi GPIO2 / SDA1 (pin 3)
  • TCA9548A SCL → Pi GPIO3 / SCL1 (pin 5)
  • A0/A1/A2 → GND for 0x70

Enable I2C with sudo raspi-config → Interface Options → I2C. Verify with i2cdetect -y 1 and look for 0x70.

Raspberry Pi Pico (3.3V logic):

  • TCA9548A VIN → Pico 3V3(OUT) (pin 36)
  • TCA9548A GND → Pico GND
  • TCA9548A SDA → GPIO4 (I2C0 SDA, pin 6)
  • TCA9548A SCL → GPIO5 (I2C0 SCL, pin 7)
  • A0/A1/A2 → GND for 0x70

I2C0 and I2C1 are both available on the Pico, and you can remap to almost any pin. Match these to whatever you use in machine.I2C(...).

Code Examples

Arduino — Channel select helper and scan all 8 channels:

#include <Wire.h>

#define TCA_ADDR 0x70

void tcaSelect(uint8_t ch) {
  if (ch > 7) return;
  Wire.beginTransmission(TCA_ADDR);
  Wire.write(1 << ch);
  Wire.endTransmission();
}

void setup() {
  Serial.begin(115200);
  Wire.begin();
  delay(100);

  for (uint8_t ch = 0; ch < 8; ch++) {
    tcaSelect(ch);
    Serial.print("Channel "); Serial.print(ch); Serial.println(":");
    for (uint8_t addr = 1; addr < 127; addr++) {
      if (addr == TCA_ADDR) continue;
      Wire.beginTransmission(addr);
      if (Wire.endTransmission() == 0) {
        Serial.print("  Found 0x"); Serial.println(addr, HEX);
      }
    }
  }
}

void loop() {}

ESP32 — Two BME280 sensors at the same address on different channels:

#include <Wire.h>
#include <Adafruit_BME280.h>

#define TCA_ADDR 0x70
Adafruit_BME280 bme;

void tcaSelect(uint8_t ch) {
  Wire.beginTransmission(TCA_ADDR);
  Wire.write(1 << ch);
  Wire.endTransmission();
}

void setup() {
  Serial.begin(115200);
  Wire.begin(21, 22);

  tcaSelect(0);
  if (!bme.begin(0x76)) Serial.println("BME on ch0 not found");

  tcaSelect(1);
  if (!bme.begin(0x76)) Serial.println("BME on ch1 not found");
}

void loop() {
  tcaSelect(0);
  Serial.printf("Ch0: %.2f C\n", bme.readTemperature());
  tcaSelect(1);
  Serial.printf("Ch1: %.2f C\n", bme.readTemperature());
  delay(1000);
}

Raspberry Pi (Python, smbus2):

from smbus2 import SMBus
import time

TCA_ADDR = 0x70
BUS = 1

def tca_select(bus, channel):
    if channel > 7: return
    bus.write_byte(TCA_ADDR, 1 << channel)

with SMBus(BUS) as bus:
    for ch in range(8):
        tca_select(bus, ch)
        time.sleep(0.05)
        print(f"Channel {ch}:")
        for addr in range(0x03, 0x78):
            if addr == TCA_ADDR:
                continue
            try:
                bus.read_byte(addr)
                print(f"  Found 0x{addr:02X}")
            except OSError:
                pass

Raspberry Pi Pico (MicroPython):

from machine import Pin, I2C
import time

i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=400000)
TCA_ADDR = 0x70

def tca_select(channel):
    if 0 <= channel <= 7:
        i2c.writeto(TCA_ADDR, bytes([1 << channel]))

for ch in range(8):
    tca_select(ch)
    time.sleep_ms(50)
    devs = i2c.scan()
    print(f"Channel {ch}: {[hex(d) for d in devs if d != TCA_ADDR]}")

Frequently Asked Questions

Why does my I2C scanner only show 0x70?
That is the TCA9548A itself, and at boot all channels are disabled, so nothing downstream is visible yet. Write 1 << channel to 0x70 first, then scan again to see the device on that channel.
Can I read from multiple channels at once?
Electrically yes — if you write a control byte like 0b00000011 you enable channel 0 and 1 simultaneously. But if both channels host the same I2C address (which is usually why you bought this), you will get bus contention. Enable one channel at a time for duplicate-address devices.
Do I need external pull-up resistors?
Most I2C sensor boards (BME280, SSD1306, MPU6050, etc.) already have 4.7k or 10k pull-ups on board, and the TCA9548A breakout has pull-ups on the master side. For short wires and a few devices per channel you are fine. If you have long cables or many devices, add a 4.7k pull-up from SDA and SCL to VCC on the child channel.
How do I use more than 8 sensors with the same address?
Add more TCA9548A boards on the same parent bus. Tie A0/A1/A2 differently on each board to get addresses 0x70 through 0x77 — that gives you up to 8 muxes × 8 channels = 64 children with the same I2C address.
Does the TCA9548A do level shifting?
Yes, each channel is independently isolated and powered from VCC, so you can run a 5V master with 3.3V children (or vice versa) as long as VCC matches the master side. Each channel sees the pull-up rail of whatever you connect to it.
What does the RESET pin do?
Pulling RESET low resets the internal channel-select register, disabling all channels. It has an internal pull-up so you can leave it floating in most cases. Wire it to a GPIO if you want a software escape hatch for a stuck I2C bus.
Why are my reads slow when switching channels?
Each channel switch is one I2C write (a couple hundred microseconds at 400 kHz). If you are polling 8 sensors back-to-back, that overhead is negligible. If you are seeing real slowness, it is usually the sensor's own conversion time (BME280 forced-mode reads take ~10 ms), not the mux.