
Over-the-Air(OTA)ファームウェア更新は、現場に展開された量産用の Bluetooth 機器にとって不可欠な要件です。設計の不備のある更新メカニズムは、デバイスを起動不能(brick)にしたり、アプリケーションデータを破損させたり、あるいはセキュリティ脆弱性を未修正のまま放置したりする恐れがあります。本記事では、nRF52 および ESP32 プラットフォーム向けのコード例とともに、転送プロトコルの選択、デュアルバンク flash 管理、およびロールバックの安全網について解説します。
OTA 転送プロトコルの比較
| プロトコル | スループット | オーバーヘッド | 通信距離 | 適している用途 |
|---|---|---|---|---|
| BLE GATT (MBU/DFU) | ~1-5 KB/s | 4 bytes(ATT ヘッダ) | ~50 m | 低消費電力のフィールドデバイス |
| BLE L2CAP | ~10-30 KB/s | 4-6 bytes | ~50 m | より高速な BLE 更新 |
| Wi-Fi HTTP | ~200-800 KB/s | TCP/IP スタック | LAN/WAN | Wi-Fi コンボ搭載モジュール |
| UART 有線 | ~115-921 KB/s | なし(シリアル) | テザリングのみ | 生産ラインの書き込み |
BLE GATT DFU は、電池駆動のモジュールにとって主流の転送手段であり続けています。Nordic の DFU over BLE は、コントロールポイント特性(UUID 8EC90001-F315-4F60-9FB8-838830DAEA50)とデータ特性(8EC90002-F315-4F60-9FB8-838830DAEA50)を使用します。最大 MTU ネゴシエーション(通常 247 bytes)により、通知付き転送時のスループットは ~2.5 KB/s に制限されます。
デュアルバンク flash アーキテクチャ
デュアルバンク方式では、アクティブな firmware と新しい firmware イメージの両方を同時に格納します。更新に失敗した場合や新しいイメージが破損していた場合、デバイスは既知の正常なバンクから起動します。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 パーティションテーブル:
# 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 イメージの署名と検証
署名されていない firmware イメージは、簡単に改ざんされる恐れがあります。Nordic の DFU では、すべてのイメージに ECDSA-P256 署名が必要です。bootloader は更新を適用する前に署名を検証します。検証に失敗した場合、デバイスは既存の firmware の実行を継続します。
| セキュリティ対策 | 実装 | オーバーヘッド |
|---|---|---|
| イメージ署名(ECDSA-P256) | 秘密鍵で .zip に署名し、bootloader が公開鍵を検証 | 64 bytes 署名 + 64 bytes 公開鍵(init パケット内) |
| SHA-256 整合性 | firmware バイナリのハッシュを init パケットに格納 | 32 bytes |
| ロールバック防止 | flash 内の単調増加バージョンカウンタ。bootloader はダウングレードを拒否 | 4 bytes(バージョンフィールド) |
| フラグメント CRC | 転送中のチャンクごとの CRC(16-bit CCITT) | フラグメントあたり 2 bytes |
ロールバックと復旧戦略
イメージ署名を行っていても、ランタイム障害が発生する可能性があります(例: 新しい firmware が起動時にクラッシュするなど)。3 段階の復旧メカニズムにより、デバイスの生存性が確保されます。
- 起動時検証: bootloader は起動ごとに app の CRC をチェックします。破損していた場合は、直前のバンクに戻ります。
- アプリケーションのヘルスチェック: 起動から 30 秒以内に、app は特定の flash ページに “health OK” フラグを書き込みます。次回の起動時にフラグが存在しない場合(書き込み前に app がクラッシュした場合)、bootloader は戻ります。
- ウォッチドッグのフォールバック: 独立したハードウェア watchdog(WDT)は、app が 8 秒以上応答しなくなった場合に MCU をリセットします。3 回連続の WDT リセットが発生すると、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(); }}
帯域幅最適化の手法
BLE GATT では、120 KB の firmware イメージを 2.5 KB/s で転送するのに約 48 秒かかります。最適化の戦略は以下のとおりです。
| 手法 | 高速化 | トレードオフ |
|---|---|---|
| デルタ更新(バイナリ diff) | 3-10x | サーバー側での diff 計算が必要。ベースイメージが一致している必要がある |
| GATT の代わりに L2CAP CoC | 4-8x | 接続パラメータのネゴシエーションが必要。互換性がやや低い |
| 圧縮(LZMA/LZ4) | 2-3x | 展開時の CPU コスト。~20 KB のスタックオーバーヘッド |
| MTU 247 + 6 同時通知 | MTU 23 比で 2x | 6 倍の通知バッファ用メモリ(6 x 247 = 約 1.5 KB) |
デルタ更新の例: バージョン間で 8 KB が変更された 120 KB の firmware の場合、バイナリパッチ(bsdiff アルゴリズム)により約 12 KB のデルタファイルが生成されます。転送時間は 48 秒から約 5 秒へと短縮され、ほぼ 10x の改善となります。
量産向け OTA パイプライン
- CI/CD が firmware バイナリ(.hex/.bin)をビルド
- 署名サーバーが ECDSA-P256 署名を適用 → 署名付き .zip を生成
- デルタジェネレーターが前リリースに対する差分パッチを作成
- OTA サーバーが firmware マニフェスト(バージョン、サイズ、CRC、URL)をホスト
- デバイスがマニフェストを確認し、デルタまたは全イメージをダウンロードして検証・適用
- デバイスが新しい firmware へ再起動。ヘルスチェックで成功を確認
OTA 中の電力バジェット
OTA 更新は電力消費が激しい処理です。平均電流 10 μA の CR2477 駆動 BLE タグは、firmware 転送のための BLE 受信中に約 15 mA まで跳ね上がります。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)
確実な OTA のためには、更新を開始する前にデバイスの残りバッテリーが >20% であることを確認してください。BLE スタックの sd_ble_gap_data_length_update() 呼び出しを MTU=247 および PHY=2M で行うと、スループットを約 10 KB/s まで向上させ、転送時間を約 12 秒に短縮できます。
OTA firmware エンジニアリングは、あらゆる量産向け Bluetoothモジュール の導入において重要な信頼性機能です。デュアルバンク アーキテクチャ、ECDSA 署名、およびヘルスチェックによるロールバックを組み合わせることで、デバイスは数百回の更新サイクルにわたって安全かつ正常に動作し続けます。当社のエンジニアリングチームは、Bluetoothモジュール プロジェクト向けに OTA アーキテクチャのレビューと署名インフラの構築を提供しています。技術相談についてはお問い合わせください。
