nRF52840 Support¶
Joypad OS supports nRF52840 as a build target for BT2USB (BLE to USB adapter) and USB2USB (USB host via MAX3421E to USB device). The nRF52840 has BLE and USB, making it a compact standalone wireless controller adapter.
Overview¶
| Feature | Pico W / Pico 2 W | ESP32-S3 | nRF52840 |
|---|---|---|---|
| Bluetooth | Classic BT + BLE | BLE only | BLE only |
| USB Output | USB Device (RP2040) | USB OTG Device | USB Device |
| USB Host | PIO-USB | No | Via MAX3421E (SPI) |
| Controllers | All BT controllers | BLE controllers only | BLE controllers only |
| Build System | pico-sdk / CMake | ESP-IDF / CMake | nRF Connect SDK / west / CMake |
| Firmware Update | Drag-and-drop (.uf2) | Drag-and-drop (.uf2) via TinyUF2 | Drag-and-drop (.uf2) |
BLE-only limitation: nRF52840 only supports BLE controllers. Classic Bluetooth controllers (DualShock 3/4, DualSense, Switch Pro in BT mode) will not work. Most modern controllers support BLE.
Supported Controllers (BLE)¶
| Controller | Status |
|---|---|
| Xbox One / Series (BLE mode) | Supported |
| 8BitDo controllers (BLE mode) | Supported |
| Switch 2 Pro (BLE) | Supported |
| Generic BLE HID gamepads | Supported |
Not Supported (Classic BT only)¶
| Controller | Why |
|---|---|
| DualShock 3 | Classic BT only |
| DualShock 4 | Classic BT only |
| DualSense | Classic BT only |
| Switch Pro | Classic BT only |
| Wii U Pro | Classic BT only |
These controllers pair over Classic BT and require the Pico W build.
Hardware¶
Supported Boards¶
| Board | UF2 Drive | UART Pins | Apps | Notes |
|---|---|---|---|---|
| Seeed XIAO nRF52840 | XIAO-SENSE |
TX=D6 (P1.11), RX=D7 (P1.12) | bt2usb | Default board |
| Adafruit Feather nRF52840 | FTHR840BOOT |
TX=D1 (P0.25), RX=D0 (P0.24) | bt2usb, usb2usb | Feather form factor |
XIAO nRF52840¶
- Ultra-compact (0.84" x 0.70"), USB-C
- Built-in BLE radio
- UF2 bootloader (double-tap reset to enter)
- Optional SSD1306 OLED via expansion board (I2C)
- Purchase
Adafruit Feather nRF52840¶
- Feather form factor (2.0" x 0.9"), USB-C
- Compatible with FeatherWings (e.g., MAX3421E USB Host FeatherWing for usb2usb)
- UF2 bootloader (double-tap reset to enter)
- Optional SSD1306 OLED FeatherWing (I2C)
- Purchase
Build & Flash¶
Prerequisites¶
This installs the nRF Connect SDK workspace via west init and west update. Requires Python 3 and pip.
Build Commands¶
From the repo root:
# BT2USB (default)
make bt2usb_seeed_xiao_nrf52840 # Build for XIAO
make bt2usb_adafruit_feather_nrf52840 # Build for Feather
# USB2USB (Feather + MAX3421E FeatherWing only)
make usb2usb_feather_nrf52840 # Build for Feather
# Flash via UF2 bootloader
make flash-bt2usb_seeed_xiao_nrf52840 # Flash XIAO
make flash-bt2usb_adafruit_feather_nrf52840 # Flash Feather
# UART serial monitor (115200 baud)
make monitor-bt2usb_seeed_xiao_nrf52840 # Monitor XIAO
make monitor-bt2usb_adafruit_feather_nrf52840 # Monitor Feather
Or from the nrf/ directory:
cd nrf
make build # Build bt2usb for XIAO (default)
make build BOARD=adafruit_feather_nrf52840 # Build for Feather
make build APP_TYPE=usb2usb BOARD=adafruit_feather_nrf52840 # usb2usb
make flash-uf2 # Flash via UF2 drive
make monitor # UART serial monitor
Flashing¶
UF2 Bootloader (recommended):
- Double-tap the reset button on the board
- A USB drive appears (
XIAO-SENSEorFTHR840BOOT) - Copy the
.uf2file to the drive, or runmake flash-<target> - Board reboots automatically into new firmware
J-Link (alternative):
Requires a Segger J-Link debug probe connected to the board's SWD pins.
Usage¶
Pairing¶
- Flash the bt2usb firmware
- The adapter starts scanning for BLE devices automatically on boot
- Put your controller into BLE pairing mode
- Once paired, the controller reconnects automatically on subsequent use
Button Controls¶
| Action | Function |
|---|---|
| Click | Start 60-second BLE scan |
| Double-click | Cycle USB output mode |
| Triple-click | Reset to default HID mode |
| Hold | Disconnect all devices and clear bonds |
Status LED¶
| LED State | Meaning |
|---|---|
| Blinking | No device connected (scanning/idle) |
| Solid on | Device connected |
USB Output Modes¶
Double-click the button to cycle through output modes: XInput, DInput, Switch, PS3, PS4/PS5.
Debugging¶
UART Console¶
UART debug output is the primary debugging method. Connect a USB-to-UART adapter to the board's UART pins:
| Board | TX Pin | RX Pin | Baud Rate |
|---|---|---|---|
| XIAO nRF52840 | D6 (P1.11) | D7 (P1.12) | 115200 |
| Feather nRF52840 | D1 (P0.25) | D0 (P0.24) | 115200 |
UART output works from boot, in fault handlers, and from ISR context — no debug probe required.
Crash Diagnostics¶
Crash dumps include register state and stack trace. Key fault codes:
- K_ERR_KERNEL_PANIC (reason=4): Software panic from
k_panic()orabort()— typically a failed assertion in BTstack - BusFault / HardFault: Hardware fault — check for null pointer dereference or stack overflow
- MPU fault: Stack overflow detected by MPU stack guard
Architecture¶
Threading Model¶
Main Thread BTstack Thread
USB device polling BLE scanning/pairing
LED status updates HID report processing
Button input Controller data → router
Storage persistence
BTstack runs in its own Zephyr thread (k_thread_create). All BLE operations happen in that thread. The main thread handles USB output, LED, and button input, yielding via k_msleep(1).
Key Differences from RP2040¶
- Zephyr RTOS instead of bare-metal dual-core
- Raw HCI passthrough — Zephyr provides the BLE controller, BTstack acts as BLE host
- TinyUSB owns USB — Zephyr USB stack is disabled; TinyUSB's
dcd_nrf5x.cdrives USB directly - NVS storage — Flash persistence uses Zephyr NVS (shared between app settings and BTstack bonds)
- MAX3421E for USB host — SPI-connected USB host IC (usb2usb only), using direct register access for ISR safety