Skip to content

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

# One-time setup: install nRF Connect SDK v3.1.0
make init-nrf

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):

  1. Double-tap the reset button on the board
  2. A USB drive appears (XIAO-SENSE or FTHR840BOOT)
  3. Copy the .uf2 file to the drive, or run make flash-<target>
  4. Board reboots automatically into new firmware

J-Link (alternative):

cd nrf && make flash-jlink

Requires a Segger J-Link debug probe connected to the board's SWD pins.

Usage

Pairing

  1. Flash the bt2usb firmware
  2. The adapter starts scanning for BLE devices automatically on boot
  3. Put your controller into BLE pairing mode
  4. 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
make monitor-bt2usb_seeed_xiao_nrf52840   # Auto-detects serial port

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() or abort() — 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.c drives 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