Skip to content

ai-e2d/JoyStick

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

E2D BLE JoyStick — ESP32 Bluetooth Game Controller

Turn a common Joystick Shield expansion board into a BLE (Bluetooth Low Energy) wireless game controller. The firmware makes the ESP32 emulate a standard BLE HID Gamepad, so phones, computers, and emulators can recognize and pair with it directly — no extra drivers required.

Full build tutorial (why the original joystick conflicts with Bluetooth, and how to remap the pins): DIY Bluetooth Joystick: Build a Truly Wireless Game Controller with the ESP32 D1 R32 (link to be added once the article is published) Maintained by e2d.tw

繁體中文說明 (Traditional Chinese README)

Bluetooth-connected to a smart TV, playing a police car chase game

🎥 Watch the demo video


Features

  • Emulates a standard BLE HID Gamepad: 2-axis analog joystick (X/Y) + 7 buttons
  • Fixes the conflict between the original Joystick Shield's A0/A1 pins (on ESP32 ADC2) and Bluetooth, by remapping to GPIO35 / GPIO34 (ADC1)
  • Connection status LED: blinks while pairing, stays solid once connected
  • Joystick center-point calibration to avoid drift-related misreads

Hardware Requirements

Component Description Buy
ESP32 D1 R32 (Type-C) WiFi + Bluetooth dual-mode board, Arduino UNO pin-compatible e2d.tw
Joystick Shield (hand-modified version, X/Y already remapped to GPIO34/35) Analog joystick + 7 button inputs e2d.tw — choose the "手工改造版 (hand-modified)" variant; the "ESP32藍牙搖桿完整組裝版 (fully assembled)" variant is also available if you'd rather skip soldering
18650 battery holder Portable power, 2 cells in series, 7.4V e2d.tw
3D-printed mount (optional) Holds the controller board and battery holder together Printing service available via the tutorial article

Pinout

Function GPIO Notes
Joystick X axis (analog) 35 ADC1, originally A0
Joystick Y axis (analog) 34 ADC1, originally A1
Button A 26
Button B 25
Button C 17
Button D 16
Button E 27
Button F 14
Joystick press switch 12
Connection status LED 2 Blinks while pairing, solid once connected

For the full explanation of why ADC2 conflicts with Bluetooth, see the tutorial article linked above.

ESP32 D1 R32 pinout diagram

ESP32 D1 R32 pinout

Joystick Shield pinout diagram

Joystick Shield pinout


Install Option 1: Build and upload with PlatformIO (for tinkerers)

⚠️ Remove the joystick shield before flashing. The joystick press switch is wired to GPIO12, which is an ESP32 boot strapping pin that determines the flash supply voltage. If the shield is still plugged in during flashing or reset, that pin may get pulled high, making the ESP32 mistakenly think it needs 1.8V (the board actually needs 3.3V), which causes flash communication to fail. Common error messages are "Failed to communicate with the flash chip" and "Packet content transfer stopped." Plug the shield back in once flashing is complete.

  1. Install PlatformIO (VS Code extension or PlatformIO Core CLI)

  2. Clone this repository and open the folder

  3. Build:

    pio run -e UNO_D1_R32
  4. Connect the ESP32 D1 R32 via USB Type-C and upload directly:

    pio run -e UNO_D1_R32 --target upload
  5. Open the serial monitor (115200 baud) to confirm the boot messages

The main firmware lives at src/E2D joypad 1.3.cpp, using lemmingdev/ESP32-BLE-Gamepad (built on top of NimBLE-Arduino).

Install Option 2: Flash directly from your browser (no dev environment needed)

If you just want to flash a pre-built .bin firmware onto the board, you don't need to install PlatformIO or the Arduino IDE. Espressif's official web tool esptool-js talks to the board directly through the browser's Web Serial API.

This repo's firmware/ folder already contains pre-built .bin files ready to flash — no build environment required.

Note: currently only Chrome / Edge are supported. Safari is not supported (Web Serial API isn't implemented there).

Steps:

  1. ⚠️ Remove the joystick shield first (same reason as above: the joystick press switch on GPIO12 is a strapping pin, and leaving it connected during flashing can cause flash communication failures)

  2. Connect the ESP32 D1 R32 to your computer via USB Type-C

  3. Open esptool-js in Chrome or Edge

  4. Click "Connect" and select the matching serial port (COM port); the default baudrate of 921600 is fine

  5. In the "Program" section, add the .bin files you need to flash along with their addresses:

    Address File
    0x1000 bootloader.bin
    0x8000 partitions.bin
    0xe000 boot_app0.bin
    0x10000 firmware.bin (main application)

    To simplify things, you can also merge the four files into a single binary first using esptool.py merge_bin, then flash just one file at address 0x0.

  6. Double-check the addresses and click "Program" to start flashing

  7. Once done, switch to the "Console" tab (115200 baud) and confirm you see serial output such as Starting BLE work! and Waiting connection

esptool-js connecting to the board

esptool-js flashing in progress

For the full walkthrough with screenshots, see the tutorial article.


Usage

  1. After flashing and powering on the board, the connection LED will blink to indicate it's waiting to pair
  2. Make sure the joystick is not touched while the board powers on (it auto-calibrates the center point at boot)
  3. On your phone or computer's Bluetooth settings, search for and pair with "E2D BLE Controller"
  4. The LED switches to solid once paired
  5. Open gamepad-tester.com in your browser to test the joystick and buttons in real time

On Windows, you can also use the built-in "Game Controllers" settings (Settings → Devices → Game controllers, then Properties → Test tab) — once paired, Windows recognizes it as a "2-axis 7-button game controller," with the crosshair moving as you push the joystick and buttons lighting up red when pressed:

Windows game controller test 1

Windows game controller test 2

Multi-device compatibility

Since the firmware emulates a standard BLE HID Gamepad, it pairs directly with smart TVs, phones, and computers alike — no extra drivers needed. Below: the controller connected to a smart TV, playing a police car chase game.

Bluetooth-connected to a smart TV, playing a police car chase game


Troubleshooting

Guru Meditation Error: Core 0 panic'ed (IllegalInstruction) on boot

If the board crashes with this error right after the BLE stack initializes, it's almost always caused by one of the following:

  • NimBLE-Arduino version too old. This project requires NimBLE-Arduino ≥ 2.5.0 when building against espressif32 platform 6.10.0 / Arduino core 3.3.7+. Earlier versions (e.g. 2.2.1) are known to crash on init with newer cores. Check platformio.ini:

    lib_deps =
        lemmingdev/ESP32-BLE-Gamepad@0.7.3
        NimBLE-Arduino @ 2.5.0
  • Corrupted NVS partition. If the board has been flashed repeatedly across different platform/library versions, the NVS (non-volatile storage) partition can end up in a bad state and trigger crashes that look unrelated to BLE. Fix by doing a full flash erase before reflashing:

    esptool.py --port COM3 erase_flash

    (or use the "Erase Flash" option in esptool-js before re-programming)

  • Build flag typo. Double-check CONFIG_BT_NIMBLE_PINNED_TO_CORE is spelled correctly in build_flags — a typo here (e.g. CONFIG_BT_MIMBLE_PINNED_TO_CORE) silently fails to apply and can cause core-pinning related crashes.

Board stuck in a boot loop (invalid header: 0xffffffff) after resetting with the shield attached

The joystick press switch is wired to GPIO12, which is also the ESP32's flash-voltage strapping pin. If you press the EN/RST button (or the board reboots) while the joystick shield is still plugged in, it can pull GPIO12 into a state that makes the board fail to boot. Hold down the joystick's press button (K) while powering on or resetting — this forces GPIO12 to the correct level and lets the board boot normally.

Project Structure

.
├── src/            Main firmware (current version: E2D joypad 1.3.cpp)
├── firmware/       Pre-built .bin files (ready to flash with esptool-js)
├── images/         Pinout diagrams and hardware reference images
└── platformio.ini  PlatformIO project configuration

References


About / Contact

This project is developed and maintained by e2d.tw.

For development boards, joystick shields, battery holders, and other electronics, as well as 3D printing services, visit our site: https://e2d.tw

License

This project is licensed under the MIT License — free to use, modify, and distribute, including commercial use.

Dependency licenses:

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages