Principally, it is not possible to connect two I2c devices with the same I2c address to the same I2c bus.
But what if you need to control two I2c devices from a micro-controller that has only one I2c bus and these two devices have the same I2c address?
In this article we give an example how you can use a multiplexer to solve exactly this problem.
The IngredientsThe example is built using an Arduino-Uno, a TCA9548A I2c multiplexer and two SCD4x sensors. In addition to this you will require four resistors with a resistance of approximately 10kOhm to pull up the I2c lines on the I2c outputs of the multiplexer. And of course you need some jumper wires to connect all the components.
An I2c multiplexer is an ordinary I2c target device with its own I2c address, an input I2c port and several output I2c ports (SCL/SDA lines).
The multiplexer is connected to the micro-controller through the input port. Any other target device can be connected to the output ports. By sending a port number to the multiplexer device the route from input to selected output becomes active. All other outputs are inactive and not visible on the I2c bus.
After a port selection, any I2c communication to other addresses than the address of the multiplexer will use this active route. The micro-controller will directly talk to the addressed device on the selected output.
Concrete setup with TCA9548AThe TCA9548A has the output ports 0 to 7. Each port has an SCL and SDA line. On the PCB these lines are labeled with SC<x> for SCL line of port x and SD<x> for SDA line of port x (x is a number in the range [0-7]).
In our example the SCD4x sensors are connected to port 2 and 4.
The input port lines are labeled with SDA and SCL.
The target address of the TCA9548A is 0x70. Alternatively you could use any other address in the range [0x70-0x77]. In order to do so you would need to connect the pins A0..A2 to VIN. Each of these pins defines a bit of the lower address nibble. If they are not connected they default to 0.
To make our example work we need to connect:
- VIN to 3.3 V supply voltage (provided by Arduino Uno)
- GND to ground (provided by Arduino Uno)
- SDA to the SDA pin of Arduino Uno. The Arduino board has pull ups. Therefore no additional pullup resistors are required.
- SCL to the SCL pin of Arduino Uno.The Arduino board has pull ups. Therefore no additional pullup resistors are required.
- SD2 to the SDA pin of sensor 1. The TCA9548A does not provide pullups for its outputs. Therefore you need to connect a 10kOhm resistor between VIN and SD2.
- SC2 to the SCL pin of sensor 1.The TCA9548A does not provide pullups for its outputs. Therefore you need to connect a 10kOhm resistor between VIN and SC2.
- SD4 to the SDA pin of sensor 2.The TCA9548A does not provide pullups for its outputs. Therefore you need to connect a 10kOhm resistor between VIN and SD4.
- SC4 to the SCL pin of sensor 2.The TCA9548A does not provide pullups for its outputs. Therefore you need to connect a 10kOhm resistor between VIN and SC4.
The other pins are not used by the example. The example code is using target address 0x70.
Figure 3 shows an schematic overview of the setup:
The final setup looks as follows:
The complete example sketch is available on github. The example is derived from the example code of the arduino-i2c-scd4x library. Instead of using one sensor, two sensors are used for measuring CO₂, temperature and humidity.
One sensor is connected to output port 2 of the multiplexer. The other one is connected to output port 4. The multiplexer is used with the target address 0x70.
/// I2c address of multiplexer
#define MULTIPLEXER_ADDRESS 0x70
/// Port numbers where sensors are attached
static uint8_t muxPort[] = {2, 4};
A new function selectI2cPort()
is added to select the output port of the multiplexer. The selection of the port is done by the following code snippet.
Wire.beginTransmission(MULTIPLEXER_ADDRESS);
size_t written = Wire.write(1 << portNr);
uint8_t i2c_error = Wire.endTransmission();
Any operations that address a specific sensor are now enclosed in a loop statement in the following way:
for (uint8_t i = 0; i < COUNT_OF(muxPort); i++){
selectI2cPort(muxPort[i]);
//.. operations with sensor on muxPort[i]
..
}
The github repository includes complete instructions on how to build and execute the example.
Now you are ready to make your own example with as many sensors as you want - enjoy!
Comments
Please log in or sign up to comment.