ESP32 default I2C and SPI pins: which GPIOs and how to change them

On many ESP32 DevKit boards the default I2C pins are GPIO 21 (SDA) and GPIO 22 (SCL), and the default SPI pins are GPIO 23, 19, 18 and 5. Other boards differ, so check yours, and set the pins in code to be safe.

What the message means

The ESP32 can route I2C and SPI to almost any pin, but each board package picks defaults. A sketch written for one board may use pins that are wired differently on yours.

Fix it in this order

  1. Look up the pinout of your exact board. Do not assume it matches a tutorial board.
  2. Set I2C pins yourself: Wire.begin(SDA_PIN, SCL_PIN). On boards with a common DevKit layout this is often Wire.begin(21, 22).
  3. For the default SPI bus (called VSPI on many boards) the common pins are SCK 18, MISO 19, MOSI 23 and CS 5. Set them with SPI.begin(sck, miso, mosi, cs) if needed.
  4. Do not use GPIO 6 to 11 (flash) or input-only GPIO 34 to 39 for SDA, SCL or outputs.
  5. Keep I2C pull-up resistors in place. Modules often have them; a bare chip needs about 4.7 kohm.
  6. Run an I2C scanner after changing pins to confirm the device answers.

Why it happens

On the common ESP32 DevKit boards the default I2C pins are SDA GPIO 21 and SCL GPIO 22. The default SPI (VSPI) pins are SCK 18, MISO 19, MOSI 23 and CS 5. Other boards, for example S2, S3 and C3, use different defaults, so check the pinout of your board.

Pins can be changed in code, for example Wire.begin(sda, scl), which is useful when a default pin clashes with something else.

If you see this, do this

You seeDo this
Scanner finds nothing after changing pinsCheck the pins are output capable and wired as set.
Works on one board, not anotherThe defaults differ. Set pins in code.

I2C device not found, ESP32 pinout for robotics, wiring checker.

Last reviewed: November 2026. These are the usual causes and the order that finds them fastest. Test on your own board; clones and cables differ.

Why this happens

The ESP32 has a GPIO matrix that can connect most peripheral signals to most pins, so I2C and SPI are not tied to fixed pads the way they are on an Uno. The Arduino core still has to pick a default for each, and it picks them per board variant. That is why the same sketch works on one ESP32 board and finds nothing on another.

SPI has a second point. A few pins are wired straight to the SPI peripheral through the IO MUX, and these direct pins are what the default VSPI pins use. Moving SPI to other pins goes through the matrix, which can limit the top clock speed. For most hobby sensors this makes no difference, but it matters for fast displays and SD cards.

How to confirm the cause

  • Print the defaults your core uses: Serial.println(SDA); Serial.println(SCL); Serial.println(MOSI); Serial.println(MISO); Serial.println(SCK); Serial.println(SS);. These constants come from your selected board definition.
  • Compare the printed numbers with the labels printed on your board. If they differ, your selected board does not match your hardware.
  • Run an I2C scanner with the pins you intend to use. If it finds the device, the bus and pull-ups work.
  • Measure the idle level of SDA and SCL with a multimeter. Both should sit near 3.3 V because of the pull-up resistors. A low reading means a short, a missing pull-up or a device holding the line.
  • Check the pin is not input-only or reserved. GPIO 34 to 39 cannot drive an output and GPIO 6 to 11 are tied to flash on common modules.

Worked example

This scanner sets the I2C pins in code, so it does not depend on the board definition. Change 21 and 22 if you wired other pins.

#include <Wire.h>
void setup() {
  Serial.begin(115200);
  Wire.begin(21, 22);          // SDA = 21, SCL = 22
}
void loop() {
  for (uint8_t a = 1; a < 127; a++) {
    Wire.beginTransmission(a);
    if (Wire.endTransmission() == 0) Serial.printf("found 0x%02X\n", a);
  }
  delay(3000);
}

Seeing found 0x3C or 0x68, for example, means the bus works on those pins. Seeing nothing means a wiring, power or pull-up fault, not a software default.

Common mistakes

  • Copying Wire.begin(); with no arguments from a tutorial and assuming it matches every board.
  • Using the pin label printed on the board without checking that the label is the GPIO number.
  • Choosing two pins for SDA and SCL where one is strapping or input-only.
  • Forgetting that two I2C devices at the same address will clash even on the right pins.

If this did not fix it

  • Missing pull-ups: add 4.7 kohm resistors from SDA and SCL to 3.3 V if the module has none.
  • A 5 V module on a 3.3 V bus: check the module voltage rating and use a level shifter if needed.
  • Wrong board package selected, so the pin numbers do not match your hardware.