|
1 |
| -# arduino-i2c-different-buses-example |
2 |
| -Tutorial how to set up different I2C buses on Arduino platform |
| 1 | +# Introduction |
| 2 | + |
| 3 | +You have a micro controller and two identical sensors, meaning that they have the same I2C address. Without a multiplexer |
| 4 | +or the possibility to configure the I2C address of the sensor, you cannot attach them to the same I2C bus. However, on a |
| 5 | +board that provides the ability to configure any GPIO pin pairs as an I2C bus, you can connect the two sensors to their |
| 6 | +own individual I2C buses. In this article, we will explain how to set up separate I2C buses for each sensor for a few different boards. |
| 7 | + |
| 8 | +# General working principle |
| 9 | + |
| 10 | +The two SCD41 sensors we want to connect have an I2C address of 0x62, which cannot be changed. Therefore, to communicate |
| 11 | +with both sensors from the micro controller, we will use a separate I2C bus for each. Each I2C bus requires one pin for |
| 12 | +the SDA line and one for the SCL line. Depending on the board and library implementation, we can either use pre-configured |
| 13 | +instances of the `Wire` library or we need to create our own instances of the `TwoWire` class and assign the pins used for |
| 14 | +SDA and SCL lines. As a final step, we will create two instances of our sensor driver class and |
| 15 | +initialize one with the first I2C bus and the other with the second I2C bus. |
| 16 | + |
| 17 | +# ESP32 DevKitC |
| 18 | + |
| 19 | +## Wiring |
| 20 | + |
| 21 | +First, we need to define the pins we will use for the two I2C buses. For I2C bus A, we can use the default I2C pins |
| 22 | +of the board. For the ESP32 DevKitC, these are pin 21 (SCL) and pin 22 (SDA). For I2C bus B, we can choose any two |
| 23 | +GPIO (General Purpose Input Output) pins. |
| 24 | + |
| 25 | +If you are using a different board, it is important to check the specifications to determine if any pins have special |
| 26 | +configurations that prevent them from being used as GPIO pins. In our case, we have selected pins 17 and 16 for |
| 27 | +I2C bus B. |
| 28 | + |
| 29 | +### Pull-up resistors |
| 30 | + |
| 31 | +Having pull-up resistors in place on the I2C data (SDA) and clock (SCL) lines is important to have a good signal quality and robust communication. You can read more about it on [I2C Pull-Up Resistors Intro](i2c-pull-up-resistors-intro.md) |
| 32 | + |
| 33 | +The ESP32 DevKitC Board ensures that GPIO lines are automatically pulled to a high state. Therefore, there is no need to |
| 34 | +manually wire or configure pull-up resistors for the pins you intend to use. |
| 35 | + |
| 36 | +### Wiring diagram |
| 37 | + |
| 38 | +Since the SCD41 sensor is compatible with both 3.3V and 5V, we can connect one sensor to the 3.3V pin and the other to |
| 39 | +the 5V pin. If both sensors require the same voltage, they can be connected through a breadboard. |
| 40 | + |
| 41 | +For this example, the wiring should be carried out as follows: |
| 42 | + |
| 43 | + |
| 44 | + |
| 45 | +- SEK-SCD41 A - Pin 1 to ESP32 Pin 22 (SCL, yellow cable) |
| 46 | +- SEK-SCD41 A - Pin 2 to ESP32 GND (Ground, black cable) |
| 47 | +- SEK-SCD41 A - Pin 3 to ESP32 3V3 (Sensor supply voltage, red cable) |
| 48 | +- SEK-SCD41 A - Pin 4 to ESP32 Pin 21 (SDA, green cable) |
| 49 | + |
| 50 | +- SEK-SCD41 B - Pin 1 to ESP32 Pin 17 (SCL, yellow cable) |
| 51 | +- SEK-SCD41 B - Pin 2 to ESP32 GND (Ground, black cable) |
| 52 | +- SEK-SCD41 B - Pin 3 to ESP32 5V (Sensor supply voltage, red cable) |
| 53 | +- SEK-SCD41 B - Pin 4 to ESP32 Pin 16 (SDA, green cable) |
| 54 | + |
| 55 | +When configuring the software later on, it is important to remember the pins allocated for the second I2C bus. |
| 56 | +Specifically, we used pin 17 for the I2C clock (SCL) and pin 16 for the I2C data (SDA). |
| 57 | + |
| 58 | +## Software setup |
| 59 | + |
| 60 | +First, you need to include the Wire library: |
| 61 | + |
| 62 | +``` |
| 63 | +#include <Wire.h> |
| 64 | +``` |
| 65 | + |
| 66 | +We are using the Arduino ESP32 platform, which includes the `Wire` library, that is already configured for |
| 67 | +the default I2C bus on pins 21/22. |
| 68 | +We can use the `Wire` instance without any modification for the sensor attached to the "I2C bus A" (default I2C bus). |
| 69 | +We just need to initialize the bus with: |
| 70 | + |
| 71 | +``` |
| 72 | +Wire.begin(); |
| 73 | +``` |
| 74 | + |
| 75 | +For the "I2C bus B" we need to configure a custom `TwoWire` instance. There is a predefined instance named `Wire1` we |
| 76 | +can configure to use the pins we defined with the following lines of code within the `setup()` function: |
| 77 | + |
| 78 | +``` |
| 79 | +const int sda_B = 16; |
| 80 | +const int scl_B = 17; |
| 81 | +Wire1.begin(sda_B, scl_B); |
| 82 | +``` |
| 83 | + |
| 84 | +Then, the code sending the commands to the sensors over the I2C bus needs to know which bus to use for which sensor. |
| 85 | +Thus, you need to configure the sensor instances accordingly. First, create a driver instance per sensor. |
| 86 | +Their scope should be global, such that those can be referred to from within `setup()` and `loop()`. |
| 87 | + |
| 88 | +``` |
| 89 | +SensirionI2cScd4x sensorA; |
| 90 | +SensirionI2cScd4x sensorB; |
| 91 | +``` |
| 92 | + |
| 93 | +Then, in the `setup()` function, assign the I2C buses to the sensors: |
| 94 | + |
| 95 | +``` |
| 96 | +sensorA.begin(Wire, SCD41_I2C_ADDR_62); |
| 97 | +sensorB.begin(Wire1, SCD41_I2C_ADDR_62); |
| 98 | +``` |
| 99 | + |
| 100 | +Look out that you really have `Wire1` assigned for sensorB, so that it uses the custom set-up I2C bus. |
| 101 | + |
| 102 | +You can now send any I2C command to the sensor, such as initiating the measurement and retrieving values. |
| 103 | + |
| 104 | +``` |
| 105 | +sensorA.startMeasurement(); |
| 106 | +sensorB.startMeasurement(); |
| 107 | +... |
| 108 | +``` |
| 109 | + |
| 110 | +You can find more details and options how to configure several I2C buses on the ESP32 platform using the Arduino IDE under [ESP32 I2C Tutorial](https://randomnerdtutorials.com/esp32-i2c-communication-arduino-ide/) |
| 111 | + |
| 112 | + |
| 113 | +## Example sketch |
| 114 | + |
| 115 | +You find a complete example under [differentI2cBusesExample.ino](differentI2cBusesExample/differentI2cBusesExample.ino). |
| 116 | +Make sure to only have the define for your board `#define ESP32_DEVKITC_V4 1` uncommented, which you find at the beginning of the sketch. |
| 117 | + |
| 118 | +# STM32 Nucleo 64 Board |
| 119 | + |
| 120 | +## Wiring |
| 121 | + |
| 122 | +The STM32 Nucleo 64 board has pre-defined I2C pins. We use I2C1 (SDA on pin 14, SCL on pin 15) and |
| 123 | +I2C2 (SDA on pin 3, SCL on pin 6). |
| 124 | + |
| 125 | +### Pull Ups |
| 126 | +The Nucleo board nor the development kit board has pull-up resistors built in. |
| 127 | +Thus, we need to wire a resistor into each of the I2C communication lines. Four 8.26kOhm resistors were used in |
| 128 | +this example and the wiring was done using a bread board so that no soldering was needed. |
| 129 | + |
| 130 | +### Wiring diagram |
| 131 | + |
| 132 | + |
| 133 | +Names R.1 to R.4 stand for resistors with a value of 8.26kOhm. |
| 134 | + |
| 135 | +- SEK-SCD41 A Pin 1 to R.1 (SCL, yellow) |
| 136 | +- R.1 to Nucleo Pin 15 (SCL, yellow) |
| 137 | +- R.1 to Nucleo 3V3 |
| 138 | +- SEK-SCD41 A Pin 2 to Nucleo GND |
| 139 | +- SEK-SCD41 A Pin 3 to Nucleo 3V3 |
| 140 | +- SEK-SCD41 A Pin 4 to R.2 (SDA, green) |
| 141 | +- R.2 to Nucleo Pin 14 (SDA, green) |
| 142 | +- R.2 to Nucleo 3V3 |
| 143 | + |
| 144 | +- SEK-SCD41 B Pin 1 to R.3 (SCL, yellow) |
| 145 | +- R.3 to Nucleo Pin 6 (SCL, yellow) |
| 146 | +- R.3 to Nucleo 3V3 |
| 147 | +- SEK-SCD41 B Pin 2 to Nucleo GND (Ground, black cable) |
| 148 | +- SEK-SCD41 B Pin 3 to Nucleo 5V (Sensor supply voltage, red cable) |
| 149 | +- SEK-SCD41 B Pin 4 to R.4 (SDA, green) |
| 150 | +- R.4 to Nucleo Pin 3 (SDA, green) |
| 151 | +- R.4 to Nucleo 3V3 |
| 152 | + |
| 153 | +What we have to remember for the configuration in the software later is the pins we used for the I2C buses. |
| 154 | + |
| 155 | +## Software setup |
| 156 | + |
| 157 | +First, you need to include the Wire library: |
| 158 | + |
| 159 | +``` |
| 160 | +#include <Wire.h> |
| 161 | +``` |
| 162 | + |
| 163 | +For configuring the I2C buses with the correct pins, we need to instantiate two TwoWire instances and pass |
| 164 | +the pins to be used for the I2C communication. |
| 165 | +Their scope should be global, thus the definition is outside `setup()` and `loop()`. |
| 166 | + |
| 167 | +``` |
| 168 | +// I2C Bus A on Pins 14 (SDA) / 15 (SCL) |
| 169 | +const int sda_A = 14; |
| 170 | +const int scl_A = 15; |
| 171 | +TwoWire i2cBusA(sda_A, scl_A); |
| 172 | +
|
| 173 | +// I2C Bus B on Pins 3 (SDA) / 6 (SCL) |
| 174 | +const int sda_B = 3; |
| 175 | +const int scl_B = 6; |
| 176 | +TwoWire i2cBusB(sda_B, scl_B); |
| 177 | +``` |
| 178 | + |
| 179 | +Then, the code sending the commands to the sensors over the I2C Bus needs to know which bus to use for which sensor. |
| 180 | +Thus, you need to configure the sensors instances accordingly. First, create a driver instance per sensor. |
| 181 | +Their scope should be global, such that they can be referred to from within `setup()` and `loop()`. |
| 182 | + |
| 183 | +``` |
| 184 | +SensirionI2cScd4x sensorA; |
| 185 | +SensirionI2cScd4x sensorB; |
| 186 | +``` |
| 187 | + |
| 188 | +Then, in the `setup()` function, assign the I2C Buses to the sensors: |
| 189 | + |
| 190 | +``` |
| 191 | +sensorA.begin(i2cBusA, SCD41_I2C_ADDR_62); |
| 192 | +sensorB.begin(i2cBusB, SCD41_I2C_ADDR_62); |
| 193 | +``` |
| 194 | + |
| 195 | +You can now send any I2C command to the sensor, such as initiating the measurement and retrieving values. |
| 196 | +The complete example code is provided in the link. |
| 197 | + |
| 198 | +``` |
| 199 | +sensorA.startMeasurement(); |
| 200 | +sensorB.startMeasurement(); |
| 201 | +... |
| 202 | +``` |
| 203 | + |
| 204 | +## Example sketch |
| 205 | + |
| 206 | +You find a complete example under [differentI2cBusesExample.ino](differentI2cBusesExample/differentI2cBusesExample.ino). |
| 207 | +Make sure to only have the define for your board `#define STM32_NUCLEO_64 1` uncommented, which you find at the beginning of the sketch. |
| 208 | + |
| 209 | +# Arduino Uno R4 WIFI |
| 210 | + |
| 211 | +# Wiring |
| 212 | + |
| 213 | +The Arduino Uno R4 WIFI provides one I2C bus on the pin header, which has no pull-ups on the board. |
| 214 | +Thus, we need to connect a pull up resistor between SDA and VDD and SCL and VDD. |
| 215 | +In the example two 2.2kOhm resistors were used. |
| 216 | + |
| 217 | +The second I2C bus is on the Qwiic. We use here the breakout board from Adafruit. |
| 218 | +The board includes 10K pull-up on SDA and SCL. |
| 219 | + |
| 220 | +### Pull Ups |
| 221 | + |
| 222 | +The Arduino Uno R4 WIFI provides no pull-ups on the board. |
| 223 | + |
| 224 | +The SEK SCD41 board we are going to connect to the I2C Bus on the pin header has no pull-up resistors built in. |
| 225 | +Thus, we need to connect a pull-up resistor between SDA and VDD and SCL and VDD. Two 8.26kOhm resistors were used in |
| 226 | +this example and the wiring was done using a bread board so that no soldering was needed. |
| 227 | + |
| 228 | +The second sensor is on a Adafruit breakout board. This one includes a pull-up resistor. Thus, |
| 229 | +no pull-up resistors have to be wired into this connection, for which a Qwiic cable is used. |
| 230 | + |
| 231 | +### Wiring diagram |
| 232 | + |
| 233 | + |
| 234 | + |
| 235 | +The list below describes the wiring, where R.1 and R.2 are resistors with a value of 8.26kOhm. |
| 236 | + |
| 237 | +- SEK-SCD41 Pin 1 to R.1 (SCL, yellow) |
| 238 | +- R.1 to Arduino Pin SCL (yellow) |
| 239 | +- R.1 to Arduino 3V3 |
| 240 | +- SEK-SCD41 Pin 2 to Arduino GND |
| 241 | +- SEK-SCD41 Pin 3 to Arduino 3V3 |
| 242 | +- SEK-SCD41 Pin 4 to R.2 (SDA, green) |
| 243 | +- R.2 to Arduino Pin 14 (green) |
| 244 | +- R.2 to Arduino 3V3 |
| 245 | + |
| 246 | +- Adafruit SCD41 to Arduino Qwiic |
| 247 | + |
| 248 | + |
| 249 | +## Software setup |
| 250 | + |
| 251 | +First, you need to include the Wire library: |
| 252 | + |
| 253 | +``` |
| 254 | +#include <Wire.h> |
| 255 | +``` |
| 256 | + |
| 257 | +For the Arduino Uno R4, this library defines two I2C buses. The first, "Wire" is configured |
| 258 | +for the SDA/SCL pins on the pin header, where "Wire1" is configured for the Qwiic connector. |
| 259 | +We can use those two instances without any further configuration. You just need to initialize them: |
| 260 | + |
| 261 | +``` |
| 262 | +Wire.begin(); |
| 263 | +Wire1.begin(); |
| 264 | +``` |
| 265 | + |
| 266 | +Then, the code sending the commands to the sensors over the I2C bus needs to know which bus to use for which sensor. |
| 267 | +Thus, you need to configure the sensor instances accordingly. First, create a driver instance per sensor. |
| 268 | +Their scope should be global, such that those can be referred to from within `setup()` and `loop()`. |
| 269 | + |
| 270 | +``` |
| 271 | +SensirionI2cScd4x sensorOnPins; |
| 272 | +SensirionI2cScd4x sensorOnQwiic; |
| 273 | +``` |
| 274 | + |
| 275 | +Next, in the `setup()` function, assign the I2C buses to the sensors: |
| 276 | + |
| 277 | +``` |
| 278 | +sensorOnPins.begin(Wire, SCD41_I2C_ADDR_62); |
| 279 | +sensorOnQwiic.begin(Wire1, SCD41_I2C_ADDR_62); |
| 280 | +``` |
| 281 | + |
| 282 | +Look out that you really have `Wire1` assigned for `sensorOnQwiic`. |
| 283 | + |
| 284 | +You can now send any I2C command to the sensor, such as initiating the measurement and retrieving values. |
| 285 | +The complete example code is provided in the link. |
| 286 | + |
| 287 | +``` |
| 288 | +sensorOnPins.startMeasurement(); |
| 289 | +sensorOnQwiic.startMeasurement(); |
| 290 | +... |
| 291 | +``` |
| 292 | + |
| 293 | + |
| 294 | +## Example sketch |
| 295 | + |
| 296 | +You find a complete example under [differentI2cBusesExample.ino](differentI2cBusesExample/differentI2cBusesExample.ino). |
| 297 | +Make sure to only have the define for your board `#define ARDUINO_UNO_R4_WIFI 1` uncommented, which you find at the beginning of the sketch. |
| 298 | + |
| 299 | +# Other Arduino Boards |
| 300 | + |
| 301 | +Documentation for Arduino boards can be found under [Arduino Wire Library](https://docs.arduino.cc/language-reference/en/functions/communication/wire/). |
| 302 | + |
| 303 | +Note that not all boards support multiple I2C buses and that it is recommended to use a custom pull-up resistor configuration, |
| 304 | +as the built in resistors are likely not strong enough (resistor value is too big). |
| 305 | + |
0 commit comments