Adafruit nRF52 bootloader with enhanced OTA DFU, forked for Meshtastic from oltaco's OTAFIX bootloader. This is the bootloader several nRF52-based Meshtastic devices ship with, and the one the Meshtastic Android app can upgrade in-app.
Current release: OTAFIX 2.5 — see changelog.md for version history.
- How this fits together
- Boards supported
- BLE advertising names
- Installation
- Bootloader upgrade from the Meshtastic Android app
- Troubleshooting
- Recommended OTA DFU settings
- Notes on Xiao NRF52840 BLE
- Notes on RAK4631 bootloader
- Notes on MeshTracker X1 DFU mode
- Contributing
- Getting help
- License
This repo builds only the bootloader — the small program that runs
before anything else on the device. It does not contain the Meshtastic
application (the LoRa mesh, BLE, and display code); that's built entirely
separately in meshtastic/firmware.
This bootloader's job is just to start that application, or, when asked,
replace it (or itself) with a new version.
On every power-up or reset, a tiny fixed piece of code at the very start of flash — Nordic's MBR — hands off to this bootloader. From there, the bootloader either:
- boots straight into the installed Meshtastic application, or
- if no valid application is installed, or the user has asked for it, waits for a new one.
A new application image — or occasionally the bootloader itself — can be installed three different ways:
| Method | Transport | Typical use |
|---|---|---|
| UF2 drag-and-drop | USB, appears as a drive | Manual flashing — see Installation |
| Serial DFU | USB, appears as a serial port | Recovery, and flashing a full bootloader+SoftDevice package with adafruit-nrfutil — see Installation |
| BLE OTA DFU | Bluetooth, no cable needed | The Meshtastic Android app's firmware/bootloader update, and any Nordic DFU app — see below and recommended settings |
There is also one thing the UF2 drive accepts that is not an image: the factory-erase file, which wipes the application's saved data in place and leaves everything else alone.
BLE OTA DFU is the only wireless path, which is what the "OTA" in "OTAFIX" refers to — and it's also the bootloader's default fallback: since OTAFIX 2.0, if no valid application is present, the device waits in BLE OTA mode automatically rather than risk getting stuck (see Troubleshooting).
The application also relies on Nordic's SoftDevice — a closed-source,
precompiled Bluetooth stack (vendored here as a hex blob under
lib/softdevice/) that sits in flash alongside it. The bootloader and the
application both call into it for BLE, so bootloader and SoftDevice
versions are usually flashed together as a matched pair (that's why the
Installation instructions below mention flashing "a full
bootloader and SoftDevice zip package").
- Elecrow ThinkNode M1
- Elecrow ThinkNode M3
- Elecrow ThinkNode M6
- Heltec T096
- Heltec T1
- Heltec T114 / HT-nRF5262
- LilyGO T-Echo
- Minewsemi MX25LE01
- MuziWorks Base Uno / Base Duo / Superbase
- Nologo ProMicro NRF52840 (aka SuperMini NRF52840)
- RAK 3401
- RAK 4631 (See note)
- RAK WisMesh Tag
- Seeed Studio SenseCAP Card Tracker T1000-E
- Seeed Studio SenseCAP MeshTracker X1 (See note)
- Seeed SenseCAP Solar Node P1
- Seeed Studio Wio Tracker L1
- Seeed Studio XIAO nRF52840 BLE (See note)
- Seeed Studio XIAO nRF52840 BLE SENSE
If there is another nRF52840-based Meshtastic board you would like to see supported, please raise a GitHub issue — or see Adding a new board in CONTRIBUTING.md if you want to submit it yourself.
When in OTA DFU mode, devices advertise using a board-specific name rather than the generic AdaDFU.
| Board | OTA DFU advertising name |
|---|---|
| Elecrow ThinkNode M1 | TNM1_DFU |
| Elecrow ThinkNode M3 | TNM3_DFU |
| Elecrow ThinkNode M6 | TNM6_DFU |
| Heltec T096 | T096_DFU |
| Heltec T1 | T1_DFU |
| Heltec T114 | T114_DFU |
| LILYGO T-Echo | LGTE_DFU |
| Minewsemi MX25LE01 | MX25_DFU |
| MuziWorks Base / Superbase | MUZI_DFU |
| ProMicro NRF52840 | PROM_DFU |
| RAK 4631 | 4631_DFU |
| RAK 3401 | 3401_DFU |
| RAK WisMesh Tag | RTAG_DFU |
| Seeed MeshTracker X1 | MTX1_DFU |
| Seeed SenseCAP Solar Node P1 | SCAP_DFU |
| Seeed T1000e | T1KE_DFU |
| Seeed WioTracker L1 | WTL1_DFU |
| XIAO NRF52 BLE / SENSE | XIAO_DFU |
The recommended way to install the bootloader is using the UF2 file.
Download the UF2 file for your board (they can be found in the releases with filenames beginning with update-), enter UF2 mode (usually by double pressing the reset button within 0.5s) and copy the UF2 file across.
If an incorrect bootloader has been flashed to the device, a full bootloader and SoftDevice zip package will need to be flashed using adafruit-nrfutil.
To wipe the device's saved data — config, node DB, keys, BLE bonds — without a serial terminal or a special erase firmware: enter UF2 mode and copy meshtastic_factory_erase.uf2 (also attached to every release) onto the drive. The bootloader erases the application's data region, then reboots straight back into UF2 mode so you can copy the firmware across next. The application itself is left in place, so if you unplug instead, it boots factory-fresh. Copy this file on its own: the drive detaches about half a second after the copy finishes (or as soon as you eject it) and comes back a second or two later.
The file is the same for every board. It is a single UF2 block with family ID 0x4D455348 and no payload; a bootloader that predates this feature ignores it silently — check INFO_UF2.TXT on the drive for a Factory-Erase: line to know whether yours supports it. Regenerate it with tools/make_factory_erase_uf2.py (or make factory-erase-uf2).
The Meshtastic Android app can flash this bootloader directly — no manual UF2 drag-and-drop needed.
With the radio connected over USB/serial (not Bluetooth), open the connected radio's configuration, go to Advanced → Firmware Update, and where an upgraded bootloader is published for your board you'll see an Upgrade bootloader option alongside Erase and reinstall. The app reads INFO_UF2.TXT from the device's update drive first to confirm the board and Bluetooth stack before writing anything, and will ask you to select the update drive twice — once for the bootloader image, once for the firmware. See the app's Firmware Updates guide for the full flow.
If the device does not show up on your computer after flashing the bootloader or performing an OTA update, it may be waiting in OTA DFU mode.
In OTAFIX 2.0 and above, OTA DFU is the default state when no valid application is present.
In this mode:
- No UF2 drive is exposed
- No serial port is available
- The device is waiting for an OTA firmware update over BLE
What to do:
- Perform an OTA update using a supported DFU app, or
- Explicitly request UF2/serial mode using double-reset.
This behaviour is intentional and prevents devices from getting stuck in UF2 mode after failed OTA updates.
If an OTA update consistently fails early with Error: Operation Failed, this is often caused by BLE stack incompatibilities when Request High MTU is enabled.
What to try:
- Experiment with different PRN settings — try 12, 8, 1, or off altogether.
- Disable Request High MTU in the DFU app.
While high MTU significantly improves performance on supported devices, it is not required for a successful OTA update.
To perform the OTA update, use nRF Device Firmware Update
(Android / iOS)
or nRF Connect
(Android / iOS).
nRF Device Firmware Update is the recommended app of the two.
For OTAFIX 2.0 and later, the following settings are recommended (these may change — feel free to experiment and report findings via a GitHub issue):
|
Packet Receipt Notification (PRN): ON Notes:
|
Recommended settings for versions prior to 2.0 can be found here.
IMPORTANT:
On older versions of the bootloader, performing an OTA update while the device was connected to a computer USB host would complete successfully but would not automatically boot into the new application firmware, requiring a manual reset.
This issue is fixed in OTAFIX 2.0.
Many of these boards are shipped with the Sense version of the bootloader installed. If your board has the Sense version installed you must use the Sense version when updating via UF2.
You can look at the INFO_UF2.TXT file on the UF2 drive to check what version is currently installed.
To check:
- Enter UF2 DFU mode (double-press reset)
- Open the
INFO_UF2.TXTfile on the mounted drive
If the file shows: "Board-ID: nRF52840-SeeedXiaoSense-v1" then the SENSE variant must be used if updating via UF2 file.
This version of the RAK4631 bootloader is based on a much newer version (0.9.2) of the Adafruit nRF52 bootloader than what RAK Wireless uses on their official bootloader (0.6.2-11). It has been tested with no problems found; whether RAK's own patches to the Adafruit bootloader introduce any behavioral difference has not been investigated. A variant of the official RAK bootloader with these patches included instead is available here.
The X1 has a single user button, and its RESET line is not exposed as a second button, so double-press reset does not work on this board. Instead, hold the primary button down while the device boots: keep holding for about 3 seconds and the bootloader enters UF2 DFU mode and mounts the mass-storage drive. Releasing the button before then boots the application as normal.
Because a momentary press belongs to the application, a short press will not enter DFU — it has to be an uninterrupted hold through boot.
To leave DFU mode, eject the mounted drive: the bootloader exits DFU and boots the application. There is no RESET button to fall back on, so this is the way out if you entered DFU and no longer want to copy firmware across. (Copying a .uf2 across also reboots the board, as on any other board.) It has to be a real eject — eject, udisksctl power-off, or Finder/Explorer "Safely Remove" — since the bootloader only sees an eject as a SCSI START STOP UNIT.
Unplugging is not a way out. The board stays in the bootloader on battery, with no LED to show it, and boots the application when you next plug it in.
Want to build from source, add a board, or submit a fix? See
CONTRIBUTING.md for the development setup and PR
process, and AGENTS.md for how the codebase is put
together.
- Questions or troubleshooting: Meshtastic Discussions
- Bug reports and feature requests: open an issue
- Security vulnerabilities: see
SECURITY.md— please do not open a public issue - General Meshtastic docs: meshtastic.org
MIT, originally Copyright (c) 2016 Adafruit Industries.