Skip to main content
Added more explanation.
Source Link
Nick Gammon
  • 38.9k
  • 13
  • 70
  • 126

Your concept sounded sensible enough so I gave it a try-out.

Multiplexed I2C

First point is: The master always generates the clock so we don't need to multiplex that. We only need to multiplex the data (SDA).

Code snippet:

// the multiplexer address select lines (A/B/C)
const byte addressA = 6; // low-order bit
const byte addressB = 5;
const byte addressC = 4; // high-order bit

int selectTarget (const byte which)
  {
  // select correct MUX channel
  digitalWrite (addressA, (which & 1) ? HIGH : LOW);  // low-order bit
  digitalWrite (addressB, (which & 2) ? HIGH : LOW);
  digitalWrite (addressC, (which & 4) ? HIGH : LOW);  // high-order bit
  }  // end of readSensor

All you have to do is call selectTarget(n) where n is 0 to 7, and you redirect SDA to the desired chip. I suggest a 4.7k pull-up on the target side so that the line is pulled high when not selected.

I tested it out and it seems to work OK.


The beauty of this setup is that you can multiplex 8 devices (eg. sensors) which happen to have the same I2C address, with only one additional chip. And, you can get 16-channel multiplexers if you want to take this further. Of course, in the code you still have to select the correct I2C address for the chip.

Your concept sounded sensible enough so I gave it a try-out.

Multiplexed I2C

First point is: The master always generates the clock so we don't need to multiplex that. We only need to multiplex the data (SDA).

Code snippet:

// the multiplexer address select lines (A/B/C)
const byte addressA = 6; // low-order bit
const byte addressB = 5;
const byte addressC = 4; // high-order bit

int selectTarget (const byte which)
  {
  // select correct MUX channel
  digitalWrite (addressA, (which & 1) ? HIGH : LOW);  // low-order bit
  digitalWrite (addressB, (which & 2) ? HIGH : LOW);
  digitalWrite (addressC, (which & 4) ? HIGH : LOW);  // high-order bit
  }  // end of readSensor

All you have to do is call selectTarget(n) where n is 0 to 7, and you redirect SDA to the desired chip. I suggest a 4.7k pull-up on the target side so that the line is pulled high when not selected.

I tested it out and it seems to work OK.

Your concept sounded sensible enough so I gave it a try-out.

Multiplexed I2C

First point is: The master always generates the clock so we don't need to multiplex that. We only need to multiplex the data (SDA).

Code snippet:

// the multiplexer address select lines (A/B/C)
const byte addressA = 6; // low-order bit
const byte addressB = 5;
const byte addressC = 4; // high-order bit

int selectTarget (const byte which)
  {
  // select correct MUX channel
  digitalWrite (addressA, (which & 1) ? HIGH : LOW);  // low-order bit
  digitalWrite (addressB, (which & 2) ? HIGH : LOW);
  digitalWrite (addressC, (which & 4) ? HIGH : LOW);  // high-order bit
  }  // end of readSensor

All you have to do is call selectTarget(n) where n is 0 to 7, and you redirect SDA to the desired chip. I suggest a 4.7k pull-up on the target side so that the line is pulled high when not selected.

I tested it out and it seems to work OK.


The beauty of this setup is that you can multiplex 8 devices (eg. sensors) which happen to have the same I2C address, with only one additional chip. And, you can get 16-channel multiplexers if you want to take this further. Of course, in the code you still have to select the correct I2C address for the chip.

Source Link
Nick Gammon
  • 38.9k
  • 13
  • 70
  • 126

Your concept sounded sensible enough so I gave it a try-out.

Multiplexed I2C

First point is: The master always generates the clock so we don't need to multiplex that. We only need to multiplex the data (SDA).

Code snippet:

// the multiplexer address select lines (A/B/C)
const byte addressA = 6; // low-order bit
const byte addressB = 5;
const byte addressC = 4; // high-order bit

int selectTarget (const byte which)
  {
  // select correct MUX channel
  digitalWrite (addressA, (which & 1) ? HIGH : LOW);  // low-order bit
  digitalWrite (addressB, (which & 2) ? HIGH : LOW);
  digitalWrite (addressC, (which & 4) ? HIGH : LOW);  // high-order bit
  }  // end of readSensor

All you have to do is call selectTarget(n) where n is 0 to 7, and you redirect SDA to the desired chip. I suggest a 4.7k pull-up on the target side so that the line is pulled high when not selected.

I tested it out and it seems to work OK.