I2C Multiplexer Shield Testing

I built an I2C multiplexer shield using an Arduino prototyping shield from SchmartBoard a couple of weeks ago. The shield uses a PCA9548A I2C multiplexer and switch chip from Texas Instruments.

One of the issues with testing I2C using Arduino is that different ICs have different Vcc requirements. While ATMega328P can be powered by either 3.3V or 5V, most Arduino boards are designed to handle only a single supply voltage. So when the supply voltage of the IC is different than that of the Arduino, a voltage level translator such as PCA9517 must be added (you can see an example here).

This is where PCA9548 comes in handy. PCA9548 has 5V tolerate IO ports and when powered with a 3.3V Vcc, it can communicate with either 3.3V or 5V powered I2C devices. And it is also very easy to use. Basically, you first select the channels you want to communicate with and then you can communicate with the I2C device as you would with it directly.

The following code example illustrates this. Here a DS1077 oscillator is connected to the first I2C channel of the PCA9548A (in this example, PCA9548A’s I2C address is set as A2 A1 A0 = 1 0 0).

#define PCA9548ADDR 0x74 //1110100
#define DS1077ADDR 0x58 //1011000

#include <Wire.h>

void setup()
  //select the first I2C Channel  
  //output a 16.67 Mhz clock on output 0
  writeDS1077Reg(0x2, 0x1E, 0x0);  //write mux register CLK/8

void loop()


void selectI2CChannels(int channels) 

void writeDS1077Reg(int cmd, int msb, int lsb) 

Function writeDS1077Reg sets the output frequency of the DS1077 oscillator to CLK/8 (16.67 Mhz). This is the only line of code needed when the device is attached to Arduino directly.

When attached to PCA9548A, the only difference in code is the selection of the channel on which DS1077 is connected to prior to calling writeDS1077Reg. This is handled via selectI2CChannels function call. This function takes in a single byte that controls which I2C channels are selected. The eight I2C channels of PCA9548A can be addressed using this command byte, with each bit representing a channel.

Multiple I2C channels can be enabled at once. For instance, if both channel 2 and channel 4 are selected the channel command byte would be B00001010, or 0xA. Once the selected channels are activated, they will remain active in subsequent I2C calls until selectI2CChannels is called again to deactivate the channel (i.e. with a 0 in the corresponding bit) or until a power reset.

Besides interfacing I2C devices requiring different supply voltages, PCA9548A is also useful when dealing with multiple I2C devices with the same device address. In this case, we can use PCA9548A to multiplex these devices by ensuring only one channel is active at any given time.

Be Sociable, Share!


  1. Vladimir says:

    Hello. Great explaining of I2C multiplexer function, thank you.
    BTW, you have an error in the link to PCA9548A datasheet (need to add ‘http://’ at the beginning).

  2. casey g says:

    Kerry – I’m working on a project where I need something like this to control 4 ADXL345’s from a single arduino, but I’m a noob when it comes to the electronics side of things. I can get my hand on ADXL345 breakout boards that use 2 different I2C addresses, but was struggling with how I would connect 4 when I only have 2 unique addresses.

    Was curious if you would recommend using the PCA9548A chip (from this write up) or the PCA9517 chip (from http://www.kerrywong.com/2011/05/08/a-dual-temperature-display-with-humidity-measurement/) to solve this?

    And either way, where do you get these chips?



  3. Reebbhaa Mehta says:

    How did you hook up the TCA9548A to your slave devices? Did you use pull up resistors? I’m having trouble figuring out the values of my pull up resistors.

  4. mario says:

    Hi Kerry !
    Congartulatios for your web site, the contens, explanatios , selected topics, smart solutions!

    i wuould like ask you the next.

    I want connect 2,3, etc FM tuners (https://www.sparkfun.com/products/10663) to one Arduino uno Rev3, i want that each fm tuner has your own frecuency (radio station), but all Si4703 Fm tuners have a only one address, , i saw your topic about the arduino shield to I2C (http://www.kerrywong.com/2012/09/19/prototyping-with-schmartboard-arduino-shield-board/) and i think that is great for this case.

    can you have a example code? , i dont know how to starter with the PCA9548A programming in arduino


  5. Sara says:


    I am using TCA9548A multiplexer and I used your code to read from 4 sensors. When I use channel 1 and 2 the multiplexer works and read the data. However, when I tried the other channels it did not work and I don’t know why! I used the hexadecimal number just like you to indicates the channel (i.e. 0x4, 0x5,…). I have 5 multiplexers and I have tried all of them and I have faced the same problem.
    Could you please help me? This very urgent


    • kwong says:

      Did you put in the correct address for each device? Basically, you first call the routine to set the channel you wanted to address, and then you will address the I2C device as if it were connected to the I2C bus directly. If you can post the code you are having issue with, I can take a look.

    • Adam says:

      I don’t know if you figured it out already, but channel 3 has to be 0x4, channel 4 0x8, channel 5 0x10. It’s best you write it in binary like: B00000001, B00000010 … etc. or in int: 2^x, where x is the channel number from 0-7.

  6. Sara says:

    I used only one multiplexer at each time. I set A0 and A1 as Low and A2 as high so that the address of the multiplexer will be 0x74. Here is the code:

    #define TCA9548AADDR 0x74 //1110100

    LSM303 compass,compass2;
    L3G gyro,gyro2;
    int AC0 = 2;
    int AC1 = 4;
    int AC2 = 7;

    void setup() {
    pinMode(AC0, OUTPUT);
    pinMode(AC1, OUTPUT);
    pinMode(AC2, OUTPUT);

    digitalWrite(AC0, LOW);
    digitalWrite(AC1, LOW);
    digitalWrite(AC2, HIGH);

    Serial.println(“initing sensor1…”);
    compass.enableDefault(); // enable default settings of the compass
    while (!gyro.init())
    Serial.println(“Failed to autodetect gyro 1 type!”);

    gyro.enableDefault(); // enable default settings of the gyroscope

    Serial.println(“initing sensor2…”);
    compass2.enableDefault(); // enable default settings of the compass
    if (!gyro2.init())
    Serial.println(“Failed to autodetect gyro 2 type!”);

    gyro2.enableDefault(); // enable default settings of the gyroscope



    void loop() {


    void selectI2CChannels(int channels)


    • kwong says:

      The code you posted looks fine. You mentioned that it only happens when you connect more than 2 devices? Curious to see whether the third device works if you swap it to the first channel and hook your gyro which was originally on channel 1 to channel 3 to see if that works. Since TCA9548 is extremely simple (you could try just use one sensor and see if you could address it using other channels), the only thing I could think of is there got to be a coding conflict (maybe in one of the libraries) somewhere.

  7. MBlanco says:

    Hello Kerry!

    I found your post really useful but I’m stuck at one point and can’t figure out how to get through.

    I was planning to use one PCA9548 to communicate with several slaves (some OLED Displays). These Displays (http://www.buydisplay.com/default/0-49-inch-oled-display-module-64×32-pixel-ssd1306-i2c-white-on-black) carry a SSD1306 driver which address is, IT SEEMS TO ME, 0x78.

    Question is, as PCA9548 has its 4 MSB defined it’s only possible to access to slaves which actually have any address between 0x70 and 0x77, am I right?

    So, summing it all up: Will I be able to connect my 0x78 slaves with that SWITCHER? I’ve been REALLY looking for any other model which may allows me to do that but til now had no success,

    hope you can’t help me!

    Thanks in advance!

    • kwong says:

      The short answer is yes. When using PCA9548, the actual device I2C address is independent from that of PCA9548. How it works is actually pretty simple, you first use PCA9458’s I2C address to select a channel with which you have your I2C device connected (e.g. the function selectI2CChannel). And after you selected your desired channel, you would communicate with your target device as if there is no mux. In other words, function writeDS1077Reg remains the same whether you use the mux or not.

      So if you connect another device to say channel 2, then you would first call selectI2CChannel and then talk to your I2C device as if you were talking to it directly. Hope it helps.

      • MBlanco says:

        Hey Kerry! Thanks for your answer. I think I got it all wrong, I thought the address you configured by A2 A1 and A0 was the address of the slave you wanted to communicate to, not the own PCA address.

        That makes everything easier as for the project I had in mind I had to use several PCA, actually!

        Thanks again for your answer.

  8. Giorgio says:

    When you posted this you probably were in love with the IRS :) Look at how you wrote “Texas Instruments” in the first paragraph :)

    However, nice post, nice blog, always useful, even if sometimes it could appear slightly stodgy for beginners.

  9. Pramit says:

    Hi K. Wong!!

    Well I am a student researcher from Germany and have been trying to use the PCA9548A chip (now marketed as TCA9548A), to accomplish I2C channel switching…

    But I have a question and am a bit stuck here that how to programmatically solve it.. I have two Humidity Sensors with addresses 0x28 (same address on both). But these humidity sensors are connected to channel 6 and channel 7 of the multiplexer chip.

    I wanted to know, when we say that we can enable 2 channels simultaneously, how can we read from two sensors connected tot these two simultaneously enabled channels, at the same time? Is this possible?? How to read these two sensors together at the same time?

    some inputs would be deeply appreciated..



    • kwong says:

      You can’t read both sensors at the same time, that’s why you need the multiplexer. Use the multiplexer to select a channel where the first sensor is connected, read the sensor as you would normally and then switch to a second channel and read your second sensor and so on.

Leave a Reply