- C 73.3%
- Python 16.5%
- CMake 6%
- Just 4.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| app | ||
| .gitignore | ||
| AGENTS.md | ||
| justfile | ||
| README.md | ||
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_SPLITcontroller in raw HCI mode - USB device stack
device_nextwith the Bluetooth HCI class (0xE0/0x01/0x01) - Board definition in
app/boards/bitcraze/crazyradio2 - Loads at 0x26000 and builds a
.uf2for 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
- Hold the button while you plug in the Crazyradio. The LED pulses red, and
a
Crazyradio2USB drive appears. - Run
just flash(theuf2west runner), or copybuild/zephyr/zephyr.uf2onto 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.