ESP32-Bit-Pirate Compatibility with Different ESP32 Variants: A Complete Hardware Support Guide
The ESP32-Bit-Pirate firmware supports multiple ESP32 variants through PlatformIO environment definitions and compile-time feature flags that conditionally include board-specific code.
This open-source hardware hacking tool by geo-tp uses a layered architecture to maintain compatibility across ESP32-S3 development kits, M5Stack devices, and custom boards—without duplicating core logic. This article explains exactly how the project achieves ESP32-Bit-Pirate compatibility with different ESP32 variants and how to build for your specific hardware.
How Multi-Board Support Works in ESP32-Bit-Pirate
The firmware employs a compile-time abstraction layer rather than runtime detection. This approach keeps the binary size minimal and eliminates performance overhead from dynamic board probing.
The Three-Layer Architecture
| Layer | Purpose | Key File |
|---|---|---|
| PlatformIO environments | Define board IDs, ESP-IDF platform, and -DDEVICE_… macros |
platformio.ini |
| Device macro selection | Instantiate the correct Board class based on the active macro |
src/main.cpp |
| Board-specific implementations | Contain hardware glue code wrapped in #if defined() guards |
src/Boards/<BoardName>/*Board.cpp |
All hardware differences—pin assignments, peripheral availability, display drivers—are expressed as pre-processor macros. The core transformers, services, and controllers remain identical across every variant.
Supported ESP32 Variants (pioarduino Branch)
The following table lists officially supported devices as defined in platformio.ini:
| Device Macro | PlatformIO board Value |
Hardware |
|---|---|---|
DEVICE_S3DEVKIT |
esp32-s3-devkitc-1 |
Generic ESP32-S3 DevKit |
DEVICE_STICKS3 |
esp32-s3-devkitc-1 (custom flags) |
M5Stack Stick S3 |
DEVICE_M5STAMPS3 |
m5stack-stamps3 |
M5Stack Stamp S3 |
DEVICE_CARDPUTER / DEVICE_CARDPUTERADV |
m5stack-stamps3 |
M5Stack Cardputer (standard & advanced) |
DEVICE_TDISPLAYS3 |
esp32-s3-devkitc1-n16r8 |
LilyGo T-Display S3 |
DEVICE_WAVESHARE_S3_GEEK |
esp32-s3-devkitc1-n16r2 |
Waveshare S3 Geek |
DEVICE_VISION_MASTER_T190 |
esp32-s3-devkitc1-n16r8 |
Heltec Vision Master T190 |
DEVICE_TEMBEDS3 / DEVICE_TEMBEDS3CC1101 |
esp32-s3-devkitc-1 |
M5Stack T-Embed S3 (with/without CC1101) |
DEVICE_XIAO_ESP32S3 |
esp32-s3-devkitc-1 |
Seeed XIAO ESP32-S3 |
DEVICE_CUSTOM |
esp32-s3-devkitc-1 |
User-defined ESP32-S3 board |
Adding a new board requires only a new [env:…] block with the appropriate -DDEVICE_… flag and optionally a small wrapper class in src/Boards/.
Building for Your ESP32 Variant
Step 1: Select the PlatformIO Environment
Run PlatformIO with the -e flag targeting your hardware:
# Generic ESP32-S3 DevKit
pio run -e s3-devkit
# M5Stack Stick S3
pio run -e m5stack-sticks3
# M5Stack Cardputer
pio run -e cardputer
# T-Display S3
pio run -e tdisplay-s3
Step 2: Configure a Custom Board (Optional)
For unsupported hardware, use the built-in custom environment. Edit the pin macros in the Custom board profile section of platformio.ini:
[env:custom]
board = esp32-s3-devkitc-1
build_flags =
-DDEVICE_CUSTOM
-DUART_RX_PIN=17
-DUART_TX_PIN=18
-DI2C_SDA_PIN=8
-DI2C_SCL_PIN=9
; -DCUSTOM_DISPLAY_DRIVER_ST7789
; -DLED_TYPE_RGB
Then build with:
pio run -e custom
Step 3: Verify Device Detection
At runtime, the firmware prints the active device in the welcome banner. In src/main.cpp around line 94, this confirms your build target:
Serial.println("Starting ESP32-Bit-Pirate on " + String(DEVICE_NAME) + " ...");
Expected output:
Starting ESP32-Bit-Pirate on DEVICE_STICKS3 ...
Code-Level Device Abstraction
Board Class Instantiation in main.cpp
The entry point uses conditional compilation to select the correct Board implementation:
// src/main.cpp (excerpt)
#include "Boards/S3DevKit/S3DevKitBoard.h"
#include "Boards/StickS3/StickS3Board.h"
#include "Boards/Cardputer/CardputerBoard.h"
// ... other board headers
#if defined(DEVICE_S3DEVKIT)
S3DevKitBoard board;
#elif defined(DEVICE_STICKS3)
StickS3Board board;
#elif defined(DEVICE_CARDPUTER) || defined(DEVICE_CARDPUTERADV)
CardputerBoard board;
#elif defined(DEVICE_CUSTOM)
CustomBoard board;
#else
#error "No device defined. Check platformio.ini build_flags."
#endif
void setup() {
board.init();
// ... common initialization
}
Peripheral Configuration with Build Flags
Peripheral pin assignments come from build_flags, not hardcoded values. Here's how UartController.cpp adapts:
// src/Controllers/UartController.cpp (excerpt)
#ifdef DEVICE_STICKS3
// Stick S3 uses UART pins 4 (RX) and 5 (TX) as defined in env
Serial1.begin(UART_BAUD, SERIAL_8N1, UART_RX_PIN, UART_TX_PIN);
#else
// All other boards use generic UART pins from env
Serial1.begin(UART_BAUD, SERIAL_8N1, UART_RX_PIN, UART_TX_PIN);
#endif
Because UART_RX_PIN and UART_TX_PIN are defined per-environment in platformio.ini, the same source compiles correctly for every board without modification.
Feature Toggles for Optional Hardware
Optional features are controlled by uncommenting -D flags in your environment:
| Flag | Enables |
|---|---|
CUSTOM_DISPLAY_DRIVER_ST7789 / SSD1306 / ILI9341 |
Display support |
LED_TYPE_RGB / LED_TYPE_SINGLE |
RGB or single-color LED |
HAS_LORA |
LoRa radio (SX1262/SX1276) |
HAS_CC1101 |
CC1101 sub-GHz transceiver |
JTAG_ENABLE |
JTAG debugging interface |
This modular approach lets you adapt a board that lacks a particular peripheral without touching source code.
Key Source Files for Understanding Compatibility
| File | What It Contains |
|---|---|
[platformio.ini](https://github.com/geo-tp/ESP32-Bit-Pirate/blob/pioarduino/platformio.ini) |
All board definitions, pin mappings, and feature flags |
[src/main.cpp](https://github.com/geo-tp/ESP32-Bit-Pirate/blob/pioarduino/src/main.cpp) |
Device macro selection and board class instantiation |
src/Boards/*/Board.h + Board.cpp |
Hardware-specific initialization (e.g., [StickS3Board.cpp](https://github.com/geo-tp/ESP32-Bit-Pirate/blob/pioarduino/src/Boards/StickS3/StickS3Board.cpp)) |
src/Controllers/*Controller.cpp |
Peripherals with conditional compilation (e.g., [UartController.cpp](https://github.com/geo-tp/ESP32-Bit-Pirate/blob/pioarduino/src/Controllers/UartController.cpp)) |
Summary
- ESP32-Bit-Pirate compatibility with different ESP32 variants is achieved through PlatformIO environments and compile-time macros, not runtime detection.
- Each board gets a unique
DEVICE_…flag (e.g.,-DDEVICE_STICKS3) that selects the correctBoardclass and peripheral configuration. - Pin assignments and optional features are controlled via
build_flagsinplatformio.ini, keeping the core codebase unified. - Adding support for new hardware requires only a new environment block and optionally a small wrapper class in
src/Boards/. - The
DEVICE_CUSTOMenvironment provides a template for unsupported ESP32-S3 boards with configurable pin mappings.
Frequently Asked Questions
What ESP32 chips does ESP32-Bit-Pirate support?
The firmware targets ESP32-S3 exclusively. All supported variants in the pioarduino branch use ESP32-S3 silicon. The original ESP32 (classic) and ESP32-C3/S2 are not supported due to peripheral and memory requirements.
How do I add support for a new ESP32-S3 board?
Create a new [env:yourboard] entry in platformio.ini with -DDEVICE_YOURBOARD, define your pin macros in build_flags, and optionally add a YourBoardBoard.cpp class in src/Boards/YourBoard/. Copy an existing board implementation as a starting template.
Why does my build fail with "No device defined"?
This error originates from the #error directive in src/main.cpp when no DEVICE_… macro is active. Verify your platformio.ini environment includes the correct -DDEVICE_… flag in build_flags and that you're building with the matching -e environment name.
Can I use the same firmware binary on different ESP32 boards?
No. Because hardware differences are resolved at compile time, you must build separate binaries for each board type. The resulting .bin file is specific to the target device and will not function correctly on different hardware.
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 →