No description
  • C 73.3%
  • Python 16.5%
  • CMake 6%
  • Just 4.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-10-12 12:58:14 +02:00
app Crazyradio 2.0 Linux HCI dongle 2026-10-12 12:58:14 +02:00
.gitignore Crazyradio 2.0 Linux HCI dongle 2026-10-12 12:58:14 +02:00
AGENTS.md Crazyradio 2.0 Linux HCI dongle 2026-10-12 12:58:14 +02:00
justfile Crazyradio 2.0 Linux HCI dongle 2026-10-12 12:58:14 +02:00
README.md Crazyradio 2.0 Linux HCI dongle 2026-10-12 12:58:14 +02:00

Crazyradio 2.0 USB Bluetooth HCI

Zephyr firmware that turns a Bitcraze Crazyradio 2.0 (nRF52840) into a standard USB Bluetooth LE controller. Linux binds it with btusb, and it shows up as an hciN device that BlueZ can use like any other dongle.

  • Zephyr v4.4.2, open-source BT_LL_SW_SPLIT controller in raw HCI mode
  • USB device stack device_next with the Bluetooth HCI class (0xE0/0x01/0x01)
  • Board definition in app/boards/bitcraze/crazyradio2
  • Loads at 0x26000 and builds a .uf2 for the stock Crazyradio 2.0 UF2 bootloader, so no debug probe is needed

Layout

app/                 manifest repo + application
  west.yml           pins Zephyr and the modules needed (cmsis, hal_nordic, segger)
  boards/bitcraze/crazyradio2/   board definition (DTS, Kconfig, runners)
  src/main.c         USB device setup, LEDs, button
zephyr/ modules/     fetched by `west update` (git-ignored)

Build

You need uv and just. The first time, run:

just setup      # venv + west + Zephyr + modules + ARM toolchain (~/zephyr-sdk-1.0.1)

Then build:

just build      # -> build/zephyr/zephyr.uf2

To do it by hand: source .venv/bin/activate.fish, then west build -b crazyradio2 app.

Flash

  1. Hold the button while you plug in the Crazyradio. The LED pulses red, and a Crazyradio2 USB drive appears.
  2. Run just flash (the uf2 west runner), or copy build/zephyr/zephyr.uf2 onto the drive.

While the HCI firmware is running, pressing the button also reboots the radio into the UF2 bootloader.

To go back to the stock Crazyradio firmware, flash Bitcraze's .uf2 the same way.

Use on Linux

lsusb | grep 2fe3:000b
btmgmt info                    # or: hciconfig -a
bluetoothctl                   # select <addr> if there are several controllers
  [bluetooth]# power on
  [bluetooth]# scan on

The nRF52840 has no public BD_ADDR, so the controller reports 00:00:00:00:00:00 and uses a static random address that is derived from the chip's FICR. If btmgmt info lists the controller as unconfigured, set an address by hand, for example sudo btmgmt -i hci1 static-addr C0:11:22:33:44:55 (a static address must have its two top bits set).

LEDs

LED Meaning
green Firmware running, waiting for the host to configure USB
blue Configured by the host (btusb bound)
red Error during USB init, or rebooting into the bootloader

nRF21540 PA/LNA

The PA/LNA is not tuned or controlled over SPI. However, the nRF21540 sits in the RF path and has no passive bypass, so it cannot be left out completely: if it is not powered and switched, the radio can neither transmit nor receive. The board devicetree therefore gives the controller the FEM's GPIOs (TX_EN, RX_EN, PDN) through &radio { fem = ... }, and the controller switches it in hardware. Two other pins are fixed with GPIO hogs:

  • MODE = high: the factory POUTB gain (~10 dB) instead of POUTA (~20 dB)
  • ANT_SEL = low: ANT1

With the SoC at 0 dBm (CONFIG_BT_CTLR_TX_PWR_0), the output at the antenna is roughly +10 dBm. Proper gain control (SPI, tx-gain-db, and so on) is left for later.

Debugging

Logs and the console go to SEGGER RTT, which needs an SWD probe on the debug pads, for example with west attach or probe-rs attach --chip nRF52840_xxAA build/zephyr/zephyr.elf.