
Las actualizaciones de firmware Over-the-Air (OTA) son un requisito indispensable para los módulos inalámbricos de producción desplegados en campo. Un mecanismo de actualización mal diseñado puede dejar los dispositivos inutilizados (brick), corromper los datos de la aplicación o dejar vulnerabilidades de seguridad sin parchear. Este artículo abarca la selección del protocolo de transporte, la gestión de flash de doble banco y las redes de seguridad de retroceso, con ejemplos de código para las plataformas nRF52 y ESP32.
Comparación de protocolos de transporte OTA
| Protocolo | Rendimiento | Sobrecarga | Alcance | Ideal para |
|---|---|---|---|---|
| BLE GATT (MBU/DFU) | ~1-5 KB/s | 4 bytes (cabecera ATT) | ~50 m | Dispositivos de campo de bajo consumo |
| BLE L2CAP | ~10-30 KB/s | 4-6 bytes | ~50 m | Actualizaciones BLE más rápidas |
| Wi-Fi HTTP | ~200-800 KB/s | Pila TCP/IP | LAN/WAN | Módulo con combo Wi-Fi |
| UART por cable | ~115-921 KB/s | Ninguna (serie) | Solo con cable | Flasheo en línea de producción |
BLE GATT DFU sigue siendo el transporte dominante para los módulos alimentados por batería. El DFU over BLE de Nordic utiliza una característica de punto de control (UUID 8EC90001-F315-4F60-9FB8-838830DAEA50) y una característica de datos (8EC90002-F315-4F60-9FB8-838830DAEA50). La negociación del MTU máximo (normalmente 247 bytes) limita el rendimiento a ~2.5 KB/s con transferencias con notificación activada.
Arquitectura de flash de doble banco
El enfoque de doble banco almacena simultáneamente tanto el firmware activo como la nueva imagen de firmware. Si la actualización falla o la nueva imagen está corrupta, el dispositivo arranca desde el banco conocido como bueno. Distribución de memoria en nRF52840 (1 MB de 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.
Tabla de particiones OTA de ESP32:
# 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
Firma y verificación de la imagen de firmware
Las imágenes de firmware sin firmar se manipulan con facilidad. El DFU de Nordic requiere firmas ECDSA-P256 en cada imagen. El bootloader verifica la firma antes de aplicar la actualización. Si la verificación falla, el dispositivo continúa ejecutando el firmware existente.
| Medida de seguridad | Implementación | Sobrecarga |
|---|---|---|
| Firma de imagen (ECDSA-P256) | La clave privada firma el .zip; el bootloader verifica la clave pública | 64 bytes de firma + 64 bytes de clave pública en el paquete init |
| Integridad SHA-256 | Hash del binario de firmware almacenado en el paquete init | 32 bytes |
| Antirretroceso (Anti-rollback) | Contador de versión monótono en flash; el bootloader rechaza la degradación | 4 bytes (campo de versión) |
| CRC de fragmento | CRC por fragmento durante la transferencia (CCITT de 16 bits) | 2 bytes por fragmento |
Estrategia de retroceso y recuperación
Incluso con la firma de imágenes, pueden producirse fallos en tiempo de ejecución (por ejemplo, el nuevo firmware se bloquea al arrancar). Un mecanismo de recuperación en tres etapas garantiza la supervivencia del dispositivo:
- Validación de arranque: El bootloader comprueba el CRC de la app en cada arranque. Si está corrupto, revierte al banco anterior.
- Comprobación de estado de la aplicación: En los 30 segundos posteriores al arranque, la app escribe una bandera «health OK» en una página específica de flash. Si la bandera está ausente en el siguiente arranque (la app se bloqueó antes de escribir), el bootloader revierte.
- Respaldo del watchdog: El watchdog de hardware independiente (WDT) reinicia el MCU si la app se queda colgada más de 8 segundos. Tres reinicios consecutivos del WDT disparan la reversión del bootloader.
// 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(); }}
Técnicas de optimización del ancho de banda
Sobre BLE GATT, transferir una imagen de firmware de 120 KB a 2.5 KB/s tarda unos 48 segundos. Estrategias de optimización:
| Técnica | Aceleración | Contrapartida |
|---|---|---|
| Actualizaciones delta (diff binario) | 3-10x | Requiere cálculo de diff en el servidor; la imagen base debe coincidir |
| L2CAP CoC en lugar de GATT | 4-8x | Requiere negociación de parámetros de conexión; menos compatible |
| Compresión (LZMA/LZ4) | 2-3x | Coste de CPU para la descompresión; ~20 KB de sobrecarga de pila |
| MTU 247 + 6 notificaciones concurrentes | 2x frente a MTU 23 | Memoria para 6x búferes de notificación (6 x 247 = ~1.5 KB) |
Ejemplo de actualización delta: Para un firmware de 120 KB con 8 KB modificados entre versiones, un parche binario (algoritmo bsdiff) genera un archivo delta de ~12 KB. El tiempo de transferencia baja de 48 segundos a ~5 segundos, una mejora de casi 10x.
Canalización OTA de producción
- CI/CD compila el binario de firmware (.hex/.bin)
- El servidor de firmas aplica la firma ECDSA-P256 → produce un .zip firmado
- El generador de delta crea un parche incremental frente a la versión anterior
- El servidor OTA aloja el manifiesto de firmware (versión, tamaño, CRC, URL)
- El dispositivo comprueba el manifiesto, descarga el delta o la imagen completa, verifica y aplica
- El dispositivo reinicia con el nuevo firmware; la comprobación de estado confirma el éxito
Presupuesto de energía durante la OTA
Las actualizaciones OTA consumen mucha energía. Una etiqueta BLE alimentada por CR2477 con una corriente media de 10 μA salta a ~15 mA durante la recepción BLE para la transferencia de firmware. Cálculo del presupuesto para una actualización de 120 KB:
# 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)
Para una OTA fiable, asegúrese de que el dispositivo tenga >20% de batería restante antes de iniciar una actualización. La llamada sd_ble_gap_data_length_update() de la pila BLE con MTU=247 y PHY=2M puede aumentar el rendimiento a ~10 KB/s, reduciendo el tiempo de transferencia a ~12 segundos.
La ingeniería de firmware OTA es una característica crítica de fiabilidad para cualquier despliegue de producción de módulo Bluetooth. La combinación de arquitectura de doble banco, firma ECDSA y retroceso con comprobación de estado garantiza que los dispositivos permanezcan seguros y funcionales a lo largo de cientos de ciclos de actualización. Nuestro equipo de ingeniería ofrece revisión de arquitectura OTA y configuración de infraestructura de firmas para proyectos de módulo Bluetooth. Contáctenos para una consulta técnica.