A lot of sensors, displays, and devices can connect over I2C. I2C is a 2-wire 'bus' that allows multiple devices to all connect on one set of pins so it's very convenient for wiring!
When using your board, you'll probably want to connect up I2C devices, and it can be a little tricky the first time. The best way to debug I2C is go through a checklist and then perform an I2C scan.
Common I2C Connectivity Issues
- Have you connected four wires (at a minimum) for each I2C device? Power the device with whatever is the logic level of your microcontroller board (probably 3.3V), then a ground wire, and a SCL clock wire, and and a SDA data wire.
- If you're using a STEMMA QT board - check if the power LED is lit. It's usually a green LED to the left side of the board.
- Does the STEMMA QT/I2C port have switchable power or pullups? To reduce power, some boards have the ability to cut power to I2C devices or the pullup resistors. Check the documentation if you have to do something special to turn on the power or pullups.
- If you are using a DIY I2C device, do you have pullup resistors? Many boards do not have pullup resistors built in and they are required! We suggest any common 2.2K to 10K resistors. You'll need two: one each connects from SDA to positive power, and SCL to positive power. Again, positive power (a.k.a VCC, VDD or V+) is often 3.3V
- Do you have an address collision? You can only have one board per address. So you cannot, say, connect two AHT20's to one I2C port because they have the same address and will interfere. Check the sensor or documentation for the address. Sometimes there are ways to adjust the address.
- Does your board have multiple I2C ports? Historically, boards only came with one. But nowadays you can have two or even three! This can help solve the "hey, but what if I want two devices with the same address" problem: just put one on each bus.
- Are you hot-plugging devices? I2C does not support dynamic re-connection, you cannot connect and disconnect sensors as you please. They should all be connected on boot and not change. (Only exception is if you're using a hot-plug assistant but that'll cost you).
- Are you keeping the total bus length reasonable? I2C was designed for maybe 6" max length. We like to push that with plug-n-play cables, but really please keep them as short as possible! (Only exception is if you're using an active bus extender).
This Feather has an LIS3DH accelerometer onboard located on address 0x18. When you perform an I2C scan with no devices connected, you will see this address appear.
Perform an I2C scan!
Install TestBed Library
To scan I2C, the Adafruit TestBed library is used. This library and example just makes the scan a little easier to run because it takes care of some of the basics. You will need to add support by installing the library. Good news: it is very easy to do it. Go to the Arduino Library Manager.
Search for TestBed and install the Adafruit TestBed library.
Now open up the I2C Scan example.
#include <Adafruit_TestBed.h> extern Adafruit_TestBed TB; #define DEFAULT_I2C_PORT &Wire // Some boards have TWO I2C ports, how nifty. We should scan both #if defined(ARDUINO_ARCH_RP2040) \ || defined(ARDUINO_ADAFRUIT_QTPY_ESP32S2) \ || defined(ARDUINO_ADAFRUIT_QTPY_ESP32S3_NOPSRAM) \ || defined(ARDUINO_ADAFRUIT_QTPY_ESP32S3) \ || defined(ARDUINO_ADAFRUIT_QTPY_ESP32_PICO) \ || defined(ARDUINO_SAM_DUE) \ || defined(ARDUINO_ARCH_RENESAS_UNO) #define SECONDARY_I2C_PORT &Wire1 #endif void setup() { Serial.begin(115200); // Wait for Serial port to open while (!Serial) { delay(10); } delay(500); Serial.println("Adafruit I2C Scanner"); #if defined(ARDUINO_ADAFRUIT_QTPY_ESP32S2) || \ defined(ARDUINO_ADAFRUIT_QTPY_ESP32S3_NOPSRAM) || \ defined(ARDUINO_ADAFRUIT_QTPY_ESP32S3) || \ defined(ARDUINO_ADAFRUIT_QTPY_ESP32_PICO) // ESP32 is kinda odd in that secondary ports must be manually // assigned their pins with setPins()! Wire1.setPins(SDA1, SCL1); #endif #if defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S2) // turn on the I2C power by setting pin to opposite of 'rest state' pinMode(PIN_I2C_POWER, INPUT); delay(1); bool polarity = digitalRead(PIN_I2C_POWER); pinMode(PIN_I2C_POWER, OUTPUT); digitalWrite(PIN_I2C_POWER, !polarity); #endif #if defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S2_TFT) pinMode(TFT_I2C_POWER, OUTPUT); digitalWrite(TFT_I2C_POWER, HIGH); #endif #if defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S2_REVTFT) pinMode(TFT_I2C_POWER, OUTPUT); digitalWrite(TFT_I2C_POWER, HIGH); #endif #if defined(ADAFRUIT_FEATHER_ESP32_V2) // Turn on the I2C power by pulling pin HIGH. pinMode(NEOPIXEL_I2C_POWER, OUTPUT); digitalWrite(NEOPIXEL_I2C_POWER, HIGH); #endif } void loop() { Serial.println(""); Serial.println(""); Serial.print("Default port (Wire) "); TB.theWire = DEFAULT_I2C_PORT; TB.printI2CBusScan(); #if defined(SECONDARY_I2C_PORT) Serial.print("Secondary port (Wire1) "); TB.theWire = SECONDARY_I2C_PORT; TB.printI2CBusScan(); #endif delay(3000); // wait 3 seconds }
Wire up I2C device
While the examples here will be using the Adafruit AHT20, a temperature and humidity sensor, the overall process is the same for just about any I2C sensor or device.
The first thing you'll want to do is get the sensor connected so your board has I2C to talk to.
Wiring the AHT20
The AHT20 comes with a STEMMA QT connector, which makes wiring it up quite simple and solder-free.
Now upload the scanning sketch to your microcontroller and open the serial port to see the output. You should see something like this:
Text editor powered by tinymce.