Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

micro:bit v2 — BLE HID keyboard (+ NUS) on nRF5 SDK

Turns a BBC micro:bit v2 (nRF52833) into a Bluetooth Low Energy keyboard:

  • Advertises as microbit kbd (HID-over-GATT / HOGP).
  • Button A → types Hello, Button B → types World.
  • Streams hello world once per second over a Nordic UART Service (NUS) notification (a simple link-alive channel).
  • 5×5 LED status display: blinking ring = advertising, steady heart = connected, X flash = re-pairing.
  • A + B together = re-match: wipes all bonds and re-advertises so a new host can pair.
  • Auto re-pair when a host reconnects with a stale key, and auto re-advertise after a disconnect.

Built on the Nordic nRF5 SDK 17.1.0 ble_app_hids_keyboard example + S140 7.2.0 SoftDevice. Only the modified files live here (see overlay/); setup.sh fetches the SDK and drops them in.


Quick start

./setup.sh            # downloads nRF5 SDK 17.1.0 + applies overlay + sets toolchain
# build:
cd sdk/nRF5_SDK_17.1.0_ddde560/examples/ble_peripheral/ble_app_hids_keyboard/pca10100/s140/armgcc
make
# flash (back in the repo root):
./flash.sh

Requirements:

  • arm-none-eabi-gcc (tested with 13.2) on PATH, or pass GNU_INSTALL_ROOT=/path/to/bin/ ./setup.sh.
  • pyocd for flashing (pip install pyocd); it has built-in nrf52833 support.
  • curl, unzip.

Repo layout

overlay/   # the only real source — modified SDK files, mirrored at SDK-relative paths
  components/boards/pca10100.h                         # micro:bit v2 button pins + LED-pin conflict fix
  examples/ble_peripheral/ble_app_hids_keyboard/
    main.c                                             # HID typing + NUS + LED matrix + re-match + auto re-pair
    pca10100/s140/config/sdk_config.h                  # RC LFCLK, NUS, attr table, VS UUID
    pca10100/s140/armgcc/Makefile                      # adds ble_nus.c, relaxes GCC13 -Werror
    pca10100/s140/armgcc/ble_app_hids_keyboard_gcc_nrf52.ld  # RAM origin bumped for NUS
setup.sh   # fetch SDK + apply overlay + configure toolchain
flash.sh   # mass-erase recover + flash SoftDevice + app + reset
test/ble_kbd_test.py   # bleak BLE-central test client (scan / NUS / HID)

The SDK is intentionally not committed (large, third-party, has its own license). setup.sh reconstructs the buildable tree under sdk/.


Hardware / pin map (micro:bit v2, nRF52833)

Function Pin(s)
Button A P0.14
Button B P0.23
LED matrix rows (anode, drive HIGH) P0.21, P0.22, P0.15, P0.24, P0.19
LED matrix cols (cathode, drive LOW) P0.28, P0.11, P0.31, P1.05, P0.30
UART log TX (→ DAPLink CDC /dev/ttyACM0, 115200) P0.06

A pixel (row, col) is lit by driving its row HIGH and column LOW; TIMER1 multiplexes one row every 3 ms.


Usage

  1. Flash, then on a phone/computer pair with microbit kbd (Just-Works, no PIN).
  2. Open a text field, press AHello, BWorld.
  3. Press A + B together to forget all bonds and pair a different host.

Test client (BLE central, no phone needed for scan/NUS)

python test/ble_kbd_test.py scan    # find 'microbit kbd'
python test/ble_kbd_test.py nus     # connect + verify 1 Hz 'hello world'
python test/ble_kbd_test.py type    # also try to read A/B HID reports

Needs pip install bleak. See the HID observability note below for type.


Gotchas (the expensive lessons)

  • No 32 kHz crystal on micro:bit v2. The SDK/DK default NRF_SDH_CLOCK_LF_SRC = 1 (external XTAL) makes the SoftDevice log "Fast advertising" while the radio never actually transmits — the device is invisible to scanners. Fix = internal RC: NRF_SDH_CLOCK_LF_SRC = 0, LF_RC_CTIV = 16, LF_RC_TEMP_CTIV = 2, LF_ACCURACY = 1 (in sdk_config.h).
  • Hardened APPROTECT. pyOCD's normal flash erase/program fails at address 0x0 with result code 0x67 (UICR 0x10001208 reads 0xFFFFFFFF). You must pyocd erase -t nrf52833 --mass (CTRL-AP ERASEALL recover) first, then flash in the same session. flash.sh does this.
  • DK LED pin vs button A. On the pca10100 board header, BSP_LED_1 == P0.14 — which is micro:bit v2's button A. Initializing LEDs (BSP_INIT_LEDS) drives P0.14 as output → button A never reads. Fix: don't init the DK LEDs (bsp_init(BSP_INIT_BUTTONS, ...)).
  • Whitelist advertising. The stock HID example advertises with a whitelist; with an empty bond list it's undiscoverable to new centrals. Set ble_adv_whitelist_enabled = false.
  • USB flashing wedges over WSL/usbip. pyocd may hang or drop mid-program (Error during board uninit). Unplug/replug the board to re-enumerate, then retry. flash.sh wraps calls in timeout.

Notes / limitations

  • Observing the HID keystrokes from a Linux/WSL BLE central is blocked when the kernel lacks uhid (no /dev/input keyboard) and BlueZ's input plugin hides the HoG characteristics from a GATT client. Verify A/B typing on a phone/Mac, or run bluetoothd --noplugin=input so test/ble_kbd_test.py type can read the raw report characteristics.
  • Stale pairing after a re-match. A BLE peripheral cannot remotely delete a host's pairing record — the "paired" entry persists on the host until it forgets the device. The firmware's auto re-pair lets such a host reconnect without a manual "forget" on macOS/Linux/phones; Windows often still needs a manual remove.

License

Project glue (overlay diffs, scripts, test client) — do as you like. The nRF5 SDK (fetched by setup.sh) is under Nordic Semiconductor's own license; not redistributed here.

About

Turn a BBC micro:bit v2 (nRF52833) into a BLE HID keyboard (+ Nordic UART link-alive) — a lean nRF5 SDK 17.1.0 / S140 overlay: button A→"Hello", B→"World", 5×5 LED status display, A+B re-pair.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages