ESP32 Pin Conflict Checker · Auto GPIO Assigner
Tick the peripherals you need and get a conflict-free GPIO plan — automatically avoiding Flash pins, strapping pins and input-only pins, with ready-to-paste Arduino init code. Works for 7 chips, 100% local.
Why ESP32 pinouts keep biting people
Every ESP32 GPIO looks interchangeable. Three classes of them are not, and none of them fail loudly — they just cost you a night of debugging:
- Flash pins — GPIO6–11 on the original ESP32, and the high-numbered pins on the S3 / C3, are wired straight to the external Flash and PSRAM. Use them as GPIO and the chip will not boot at all.
- Strapping pins — GPIO0, 2, 5, 12 and 15 (ESP32) are sampled at power-up to decide the boot mode. If your circuit pulls one the wrong way, the board boots unpredictably.
- Input-only pins — ESP32 GPIO34–39 can only read, and they have no internal pull-up. Put I2C SDA/SCL or a OneWire bus on them without external resistors and the bus works only sometimes.
Then there is the one everybody hits: ADC2 cannot be used while Wi-Fi is running (ESP32 GPIO0/2/4/12–15/25–27). Readings come back garbage. For battery monitoring, stick to ADC1 (GPIO32–39).
About the GPIO matrix
Most digital peripherals on the ESP32 can be routed to any usable pin through the GPIO matrix, so every plan this tool produces is functionally valid. Only a few speed-critical cases (80 MHz SPI, the camera DVP interface) need the fixed IO_MUX pins — check the Espressif Technical Reference Manual for those.
Need it offline?
There is a single-file offline version — one HTML file you double-click and it just works. No network, nothing uploaded. Handy in the lab, on a plane, or at a customer site with no signal.
Download esp32-pin-planner.html →
Embed this tool
Writing a blog post or answering a forum thread? Embed it — the attribution link comes along automatically.
<iframe src="https://espio.dev/embed/pinmap/" width="100%" height="640" frameborder="0" loading="lazy" title="pinmap calculator" style="border:1px solid #e3e6ea;border-radius:10px"></iframe>