A utility to perform Legacy Device Firmware Updates (DFU) on Nordic Semiconductor nRF51/nRF52 devices using Python.
This project has been split into a modular library, a Command Line Interface (CLI), and a Graphical User Interface (GUI). It is designed to replicate the logic of the official Nordic Android DFU Library, specifically handling the Buttonless Jump and Legacy DFU protocols via Bleak.
dfu_lib.py: The core library containing all DFU logic and Bluetooth operations.dfu_cli.py: The command-line interface.dfu_gui.py: A Tkinter-based GUI with real-time device scanning.
- Dual Interface: Choose between a scriptable CLI or a user-friendly GUI.
- Multi-Device Targeting (CLI): Specify multiple target names or addresses; the tool will connect to the first one found.
- Persistent Scanning: The
--waitflag allows the CLI to loop indefinitely until a target device appears. - Buttonless DFU: Automatically switches the device from Application mode to Bootloader mode.
- Legacy DFU Protocol: Supports the standard Nordic Legacy DFU process (SDK < 12 or Adafruit Bootloader).
- All Firmware Types: Auto-detects firmware type from the ZIP manifest — Application, Bootloader, SoftDevice, or combined SoftDevice+Bootloader.
- Configurable MTU: High-MTU mode (large BLE packets) can be enabled for faster transfers; disabled by default for maximum compatibility.
- Tunable: Configurable Packet Receipt Notification (PRN), timeouts, retries, and transmission delays.
- Python 3.9 or higher.
- A Bluetooth Low Energy (BLE) adapter.
- Download pre-built GUI binary from releases
- Linux only: make it executable
chmod +x NordicDFU-Linux-x64orchmod +x NordicDFU-Linux-arm64 - Execute the binary
or
- Clone or download this repository.
- Install Python dependencies:
pip install bleak- Linux Users Only: You may need to install Tkinter explicitly for the GUI:
sudo apt-get install python3-tkThe GUI allows you to scan for devices, filter by signal strength (RSSI), and configure settings visually.
python dfu_gui.pySteps:
- Browse ZIP: Select your firmware package. The firmware type (Application, Bootloader, SoftDevice, or SoftDevice+Bootloader) is detected automatically from the ZIP manifest.
- Settings:
- Force Scan: (Default: On) Forces a fresh discovery to find device services.
- PRN: (Default: 8) Packet Receipt Notification interval.
- Scan Timeout: (Default: 5s) How long to search for devices.
- High MTU: (Default: Off) Enables high-MTU negotiation for faster transfers using large BLE packets. Locked off and grayed out on macOS.
- Scan Devices: Click to populate the list. Devices are sorted by signal strength.
- Select Device: Click on the target device in the list.
- Start Update: Begins the DFU process. Check the "Log" window for details.
The CLI is ideal for scripts, headless environments, or mass deployment.
python dfu_cli.py <zip_file> <device_1> [device_2 ...] [options]| Argument | Description |
|---|---|
file |
Path to the .zip firmware file. Firmware type is auto-detected from the manifest. |
device |
One or more BLE names (e.g., MyDevice) or MAC Addresses. The tool will scan for all provided identifiers. |
--wait |
Loop indefinitely scanning for the provided device(s) until one is found. |
--retry <N> |
Number of connection/update attempts if failures occur (Default: 3). |
--scan |
Force a scan for the device even if a MAC address is provided (Recommended). |
--prn <N> |
Packet Receipt Notification interval. Default is 8. |
--delay <S> |
Critical: Delay in seconds between "Start DFU" and "Firmware Size". Default is 0.4. |
--high-mtu |
Enable high-MTU negotiation for faster transfers (disabled by default). |
--verbose |
Enable debug logging to see detailed BLE traffic. |
1. Basic Update (Single Device):
python dfu_cli.py --scan firmware.zip MyDevice2. Target Multiple Devices (First Found): This is useful if your devices might have different names or if you want to update whichever device appears first.
python dfu_cli.py firmware.zip DeviceA DeviceB AA:BB:CC:11:22:333. Wait for a device to appear (Persistent Mode):
This will keep scanning in a loop until MyDevice starts advertising.
python dfu_cli.py --wait --scan firmware.zip MyDevice4. Update a slow device with custom retries:
python dfu_cli.py --delay 0.6 --prn 4 --retry 5 firmware.zip MyDeviceYou can compile this tool into a standalone executable (.exe, .app, or Linux binary) using PyInstaller.
- Install PyInstaller:
pip install pyinstaller
- Build the GUI:
pyinstaller dfu_gui.py --onefile --windowed --name "NordicDFU"- The output will be in the
dist/folder. --windowedhides the console window.--onefilebundles everything into a single file.
- The output will be in the
The tool automatically detects the firmware type from the manifest.json inside the ZIP. The following manifest keys are supported:
| Manifest key | DFU mode | Size packet sent |
|---|---|---|
application |
Application (0x04) | [0, 0, app_size] |
bootloader |
Bootloader (0x02) | [0, bl_size, 0] |
softdevice |
SoftDevice (0x01) | [sd_size, 0, 0] |
softdevice_bootloader |
SoftDevice + Bootloader (0x03) | [sd_size, bl_size, 0] |
For softdevice_bootloader, the manifest entry must include sd_size and bl_size fields so the tool can report the correct individual image sizes to the bootloader:
{
"manifest": {
"softdevice_bootloader": {
"bin_file": "sd_bl.bin",
"dat_file": "sd_bl.dat",
"sd_size": 151552,
"bl_size": 32768
}
}
}If no manifest.json is present, the tool falls back to filename detection: files containing bootloader, softdevice, or application in their name are matched accordingly.
- GUI: Ensure "Force Scan" is checked.
- CLI: Use the
--scanflag. If the device is not currently advertising, add--waitto keep searching. - Linux: Ensure your user has permissions to access the Bluetooth controller (add user to
bluetoothgroup).
This occurs when the computer sends the firmware size packet before the device has finished processing the "Start" command.
- Fix: Increase the delay using
--delay 0.6or higher.
- Try reducing the PRN value:
--prn 4or--prn 1. This slows down the upload but ensures the device acknowledges packets more frequently.
- High-MTU mode is disabled by default. If transfers stall or produce errors, ensure it is off (do not pass
--high-mtuon the CLI; leave High MTU unchecked in the GUI). - On macOS (CoreBluetooth), explicit MTU negotiation is not supported. The High MTU option is locked off on macOS regardless of the flag.
Tested with:
- Adafruit nRF52 Bootloader (Used in Adafruit Feather, Seeed XIAO nRF52, RAK4631, etc.).
- Nordic SDK 11/12 Legacy Bootloaders.
Note: This tool does not support the "Secure DFU" protocol introduced in Nordic SDK 12+. It supports "Legacy DFU" only.
This utility is a Python implementation based on logic from the open-source Nordic Semiconductor Android DFU Library.
Use at your own risk. Ensure you have recovery mechanisms (e.g., a physical access to board USB, SWD interface) available when performing firmware updates.