ESP32-Bit-Pirate Pinout Diagram for I2C and SPI: Complete GPIO Mapping Guide
The ESP32-Bit-Pirate uses fixed GPIO assignments defined in src/Adapters/Bpio2Adapter.h: I²C on GPIO 17 (SCL) and GPIO 18 (SDA), SPI on IO0 (CS), IO1 (CLK), IO2 (MOSI), and IO3 (MISO).
The ESP32-Bit-Pirate is an open-source firmware that turns ESP32-S3 development boards into a multi-protocol debugging tool. Whether you're bus-pirating I²C EEPROMs or flashing SPI flash chips, understanding the pinout diagram for I2C and SPI is essential for correct wiring. This guide breaks down the exact GPIO mappings, their source locations in the firmware, and how to customize them for your hardware.
Default I²C Pinout on ESP32-S3
The I²C interface uses a dedicated two-wire bus with pull-up capable pins on the ESP32-S3.
| Signal | GPIO | Source Location |
|---|---|---|
| SCL | GPIO 17 | Bpio2Adapter.h line 24 |
| SDA | GPIO 18 | Bpio2Adapter.h line 25 |
These values are hardcoded as I2C_SCL_PIN and I2C_SDA_PIN in the adapter header. The firmware supports I²C frequencies from 1 kHz to 1 MHz and transfers up to 128 bytes per transaction, defined by MIN_I2C_FREQUENCY, MAX_I2C_FREQUENCY, and MAX_I2C_TRANSFER constants in the same file.
Default SPI Pinout on ESP32-S3
The SPI interface shares clock and data lines with the I²C pins but adds dedicated chip-select and MISO lines.
| Signal | GPIO | Pin Alias | Source Location |
|---|---|---|---|
| CLK | GPIO 17 | IO1 | Comment line 20 (shares I²C SCL) |
| MOSI | GPIO 18 | IO2 | Comment line 21 (shares I²C SDA) |
| MISO | GPIO 3 | IO3 | Enum line 39 |
| CS | GPIO 0 | IO0 | Enum line 39 |
The IO0–IO3 naming refers to the logical pin positions on the Bit-Pirate's 10-pin header, not the ESP32-S3 GPIO numbers. This abstraction allows the firmware to present a consistent interface across different board variants.
How the Pinout Is Enforced at Runtime
The pin-mapping layer centralizes all hardware definitions. When you execute mode I2C or mode SPI from the CLI, the firmware:
- Loads the protocol-specific mapping from
Bpio2Adapter.h - Initializes the ESP-IDC GPIO driver with the defined pins
- Updates the UI via
PinoutTransformer— retrieved throughDependencyProvider::getPinoutTransformer()
The ActionDispatcher.cpp file handles the UI update trigger (see the comment "Show pinout for the mode"). This guarantees that the web interface always reflects active pin assignments, eliminating guesswork about which GPIOs are currently in use.
Visual Pinout Reference
The project includes animated documentation for the I²C configuration:

SPI uses the same physical IO0–IO3 header positions. For board-specific wiring photos, consult the "Pinout" section of the hardware-guide wiki.
Practical Code Examples
Enter I²C Mode and Scan the Bus
// Serial or web terminal
mode I2C
scan
The scan command probes all 7-bit addresses (0x01–0x7F) using the default GPIO 17/18 pins.
Read from an I²C EEPROM
#include "src/Services/I2cService.h"
I2cService i2c;
i2c.begin(); // Configures GPIO17/18 automatically
uint8_t buffer[4];
i2c.readBytes(0x50, 0x00, buffer, 4); // Device 0x50, address 0x00
The I2cService class abstracts the ESP-IDF I²C driver. All pin configuration is delegated to the adapter layer.
Flash an SPI Chip
// CLI mode switch
mode SPI
flash write 0x0000 firmware.bin
The flash command uses the SPI pins (IO0–IO3) with the CS on GPIO 0 for chip selection.
Customizing the Pinout for Your Board
Not all ESP32-S3 boards expose GPIO 17/18. Override defaults at compile-time via platformio.ini:
build_flags = -DI2C_SCL_PIN=21 -DI2C_SDA_PIN=22
After rebuilding, the firmware routes I²C to GPIO 21 (SCL) and GPIO 22 (SDA). SPI pins remain fixed on IO0–IO3 unless you modify the enum definitions in Bpio2Adapter.h directly.
Requirement: The target board must provide minimum 8 MB flash for the firmware image.
Key Source Files Reference
| File | Purpose |
|---|---|
src/Adapters/Bpio2Adapter.h |
Central pin definitions and protocol limits |
src/Controllers/I2cController.h |
I²C command handlers (scan, read, write) |
src/Providers/DependencyProvider.cpp |
PinoutTransformer factory for UI updates |
src/Dispatchers/ActionDispatcher.cpp |
Mode switch and pinout display triggers |
Summary
- I²C pins: GPIO 17 (SCL), GPIO 18 (SDA) — defined in
Bpio2Adapter.hlines 24–25 - SPI pins: IO0/CS (GPIO 0), IO1/CLK (GPIO 17), IO2/MOSI (GPIO 18), IO3/MISO (GPIO 3)
- Frequency range: 1 kHz – 1 MHz for I²C, with 128-byte maximum transfers
- Runtime enforcement:
PinoutTransformerensures UI sync with active GPIO configuration - Customization: Override via
platformio.inibuild flags or direct header edits
Frequently Asked Questions
Can I use I²C and SPI simultaneously on ESP32-Bit-Pirate?
No. The firmware operates in single-protocol modes. Switching with mode I2C or mode SPI reconfigures the GPIO matrix for the active protocol. The shared CLK/MOSI pins (GPIO 17/18) would create bus conflicts if both protocols ran concurrently.
Does the pinout work on ESP32 (non-S3) boards?
Partially. The ESP32-Bit-Pirate targets ESP32-S3 specifically for its USB-OTG capabilities and memory layout. While the GPIO numbers may function on classic ESP32, the firmware is compiled and tested against S3 silicon. Use the official S3 Dev-Kit, LILYGO T-Display S3, or M5 Atom S3 Lite for guaranteed compatibility.
How do I verify my wiring matches the active pinout?
Launch the web UI after selecting a mode. The PinoutTransformer renders the current GPIO mapping based on DependencyProvider::getPinoutTransformer(). Cross-reference with the animated I²C GIF in images/i2c.gif and the header positions IO0–IO3 documented in the wiki.
What happens if I override pins to values already used by SPI?
Avoid overlap. The adapter does not validate GPIO collisions at compile-time. If you set I2C_SCL_PIN=0 (SPI CS) or I2C_SDA_PIN=3 (SPI MISO), runtime behavior is undefined. Keep I²C overrides on GPIOs outside the IO0–IO3 range unless you intend to sacrifice SPI functionality.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →