Over-the-air (OTA) firmware updates are a non-negotiable requirement for production Bluetooth modules deployed in the field. A poorly designed update mechanism can brick devices, corrupt application data, or leave security vulnerabilities unpatched. This article covers transport protocol selection, dual-bank flash management, and rollback safety nets with code examples for nRF52 and ESP32 platforms.
OTA Transport Protocol Comparison
| Protocol | Throughput | Overhead | Range | Best For |
|---|---|---|---|---|
| BLE GATT (MBU/DFU) | ~1-5 KB/s | 4 bytes (ATT header) | ~50 m | Low-power field devices |
| BLE L2CAP | ~10-30 KB/s | 4-6 bytes | ~50 m | Faster BLE updates |
| Wi-Fi HTTP | ~200-800 KB/s | TCP/IP stack | LAN/WAN | Module with Wi-Fi combo |
| UART wired | ~115-921 KB/s | None (serial) | Tethered only | Production line flashing |
BLE GATT DFU remains the dominant transport for battery-powered modules. Nordic’s DFU over BLE uses a control point characteristic (UUID 8EC90001-F315-4F60-9FB8-838830DAEA50) and a data characteristic (8EC90002-F315-4F60-9FB8-838830DAEA50). Maximum MTU negotiation (typically 247 bytes) limits throughput to ~2.5 KB/s with notification-enabled transfers.
Dual-Bank Flash Architecture
The dual-bank approach stores both the active firmware and the new firmware image simultaneously. If the update fails or the new image is corrupt, the device boots from the known-good bank. Memory layout on nRF52840 (1 MB flash):
// nRF52840 dual-bank layout (SoftDevice S140)
// Bank 0 (active): 0x00026000 - 0x0005FFFF (214 KB app + 2 slots)
// Bank 1 (update): 0x00060000 - 0x0009FFFF (262 KB)
// SoftDevice: 0x00000000 - 0x00025FFF (152 KB)
// Bootloader: 0x000F8000 - 0x000FFFFF (32 KB)
// Minimum image size for dual-bank: (flash_total - SD - BL) / 2
// = (1048576 - 152000 - 32768) / 2 = 431904 bytes (~421 KB per bank)
// For typical BLE apps (~80-120 KB), dual-bank easily fits.
ESP32 OTA partition table:
# ESP32 partition table (single-bank OTA fallback)
# Name, Type, SubType, Offset, Size
nvs, data, nvs, 0x9000, 0x4000
otadata, data, ota, 0xd000, 0x2000
phy_init, data, phy, 0xf000, 0x1000
factory, app, factory, 0x10000, 1M
ota_0, app, ota_0, 0x110000, 1M
ota_1, app, ota_1, 0x210000, 1M
# otadata stores which partition (ota_0 or ota_1) is active
Firmware Image Signing and Verification
Unsigned firmware images are trivially tampered with. Nordic’s DFU requires ECDSA-P256 signatures on every image. The bootloader verifies the signature before applying the update. If verification fails, the device continues running the existing firmware.
| Security Measure | Implementation | Overhead |
|---|---|---|
| Image signing (ECDSA-P256) | Private key signs .zip; bootloader verifies public key | 64 bytes signature + 64 bytes public key in init packet |
| SHA-256 integrity | Hash of firmware binary stored in init packet | 32 bytes |
| Anti-rollback | Monotonic version counter in flash; bootloader rejects downgrade | 4 bytes (version field) |
| Fragment CRC | Per-chunk CRC during transfer (16-bit CCITT) | 2 bytes per fragment |
Rollback and Recovery Strategy
Even with image signing, runtime failures can occur (e.g., new firmware crashes on boot). A three-stage recovery mechanism ensures device survivability:
- Boot validation: Bootloader checks app CRC on every boot. If corrupt, revert to previous bank.
- Application health check: Within 30 seconds of boot, the app writes a « health OK » flag to a specific flash page. If the flag is absent on next boot (app crashed before writing), bootloader reverts.
- Watchdog fallback: Independent hardware watchdog (WDT) resets the MCU if the app hangs for >8 seconds. Three consecutive WDT resets trigger bootloader revert.
// nRF52: Health check implementation
#define HEALTH_ADDR 0x000FE000 // Dedicated flash page for health flag
#define HEALTH_MAGIC 0xDEADBEEF
void app_health_check(void) {{
uint32_t val = 0xDEADBEEF;
sd_flash_write((uint32_t*)&val, HEALTH_ADDR, 1);
}}
// Bootloader check (in DFU bootloader):
// if (flash_read(HEALTH_ADDR) != HEALTH_MAGIC) {{ revert_bank(); }}
Bandwidth Optimization Techniques
Over BLE GATT, transferring a 120 KB firmware image at 2.5 KB/s takes ~48 seconds. Optimization strategies:
| Technique | Speedup | Trade-off |
|---|---|---|
| Delta updates (binary diff) | 3-10x | Requires server-side diff computation; base image must match |
| L2CAP CoC instead of GATT | 4-8x | Requires connection parameter negotiation; less compatible |
| Compression (LZMA/LZ4) | 2-3x | CPU cost for decompression; ~20 KB stack overhead |
| MTU 247 + 6 concurrent notifications | 2x vs MTU 23 | Memory for 6x notification buffers (6 x 247 = ~1.5 KB) |
Delta update example: For a 120 KB firmware with 8 KB changed between versions, a binary patch (bsdiff algorithm) produces a ~12 KB delta file. Transfer time drops from 48 seconds to ~5 seconds—nearly 10x improvement.
Production OTA Pipeline
- CI/CD builds firmware binary (.hex/.bin)
- Signing server applies ECDSA-P256 signature → produces signed .zip
- Delta generator creates incremental patch against previous release
- OTA server hosts firmware manifest (version, size, CRC, URL)
- Device checks manifest, downloads delta or full image, verifies, applies
- Device reboots into new firmware; health check confirms success
Power Budget During OTA
OTA updates are power-intensive. A CR2477-powered BLE tag with 10 μA average current jumps to ~15 mA during BLE receive for firmware transfer. Budget calculation for a 120 KB update:
# OTA power budget
IMAGE_SIZE = 120000 # bytes
THROUGHPUT = 2500 # bytes/sec (BLE GATT)
TRANSFER_TIME = IMAGE_SIZE / THROUGHPUT # = 48 seconds
RX_CURRENT = 15e-3 # 15 mA during RX
VOLTAGE = 3.0 # CR2477 nominal
CHARGE_CONSUMED = RX_CURRENT * TRANSFER_TIME / 3600 # = 0.0002 Ah = 200 μAh
# CR2477 capacity: 1000 mAh
# OTA consumes 0.02% of total battery per update
# With monthly updates: 0.24% annual OTA budget (negligible)
For reliable OTA, ensure the device has >20% remaining battery before starting an update. The BLE stack’s sd_ble_gap_data_length_update() call with MTU=247 and PHY=2M can increase throughput to ~10 KB/s, cutting transfer time to ~12 seconds.
OTA firmware engineering is a critical reliability feature for any production Bluetooth module deployment. The combination of dual-bank architecture, ECDSA signing, and health-check rollback ensures devices stay secure and functional across hundreds of update cycles. Our engineering team provides OTA architecture review and signing infrastructure setup for Bluetooth module projects—contact us for a technical consultation.