LoginSignup
7
13

More than 3 years have passed since last update.

nRF52でBLEデバイスを開発する(2)OTAアップデート Buttonless DFUとSecure DFU

Posted at

 この記事はnRF52でBLEデバイスを開発する(1)Adafruit FeatherとSEGGER Embeded Studioの続きです。

OTAアップデート

 BLEデバイスを開発するので、何はなくともOTAアップデートが必要です。(断言

概要

 まず、公式ドキュメント。
 https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v15.3.0/lib_bootloader_modules.html

bootloader_memory_nrf52.png

https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v15.3.0/lib_bootloader.html よりメモリマップを引用
 この図は、nRF52内蔵のフラッシュのメモリマップです。
 プロセッサが起動すると、まずMBRが実行されます。MBR内にBootloaderのアドレスが記録されていると、Bootloaderを起動します。
 SDKのサンプルアプリのほとんどはBootloaderなしで直接起動するように作られていますが、DFU(Device Firmware Update - nRF52でのOTAのこと)を実装する際は、Bootloaderを準備する必要があります。

まず、DFUの動作をざっくりと解説します。

  1. アプリがDFU開始のシグナルを受け取る
  2. アプリはDFU開始ステータスをFLASHに書き込み、再起動
  3. Bootloaderが起動する
  4. BootloaderはDFU開始ステータスをチェックし(*1)、DFUモードで起動する(アプリは起動しない)
  5. Bootloaderはアドバタイズを開始する(*2)
  6. DFUを行うCentralがBootloaderに接続する
  7. ダウンロード開始。受信したデータはフラッシュのFree領域に格納される
  8. 全てのデータを受信したら、エラーのチェック後、受信データをアプリ領域に転送。
  9. 再起動
  10. 転送されたアプリが起動する

*1 DFU開始ステータスをチェックする方法が複数用意されています。

  • 基板上のボタンを押されている
  • リセットボタンを押されている
  • 電源管理レジスタの特定のビットが立っている
  • ボタンレスDFUモードが設定されている

*2 DFUの通信手段もANT,UART,BLE,USBと色々用意されていますが、本稿ではBLEのみ解説します。必要な人はサンプルソースを読んでください。

Buttonless DFU

 ボタンレスDFUでは、アプリケーション側で特定のCharacteristicを開けておき、そこへのアクセスに対応してDFUシーケンスが開始されることになります。スマートホンのアプリ主導でファームウェアアップデートが行えることになります。

Secure DFU

 nRF52 SDKでは偽のファームウェアによる攻撃を防ぐために、Secure DFUという手段が用意されています。
 ダウンロードするファイルを秘密鍵で署名-Bootloader内の公開鍵で署名を検証、という形で、正規のファームかどうかを識別する仕組みです。
 これによって、偽装ファームによる攻撃を防ぐことが可能となります。
(本記事では割愛しますが、デバッガ接続時のリードライトを禁止する手段も用意されています)

Bootloaderの実装

 まず、こちらの記事を参照してください。
 nrf52でOTAする(Secure Bootloader+DFU)
 https://qiita.com/chabose/items/dab0b12f460f85918c8d

 上記記事と重複する内容はスキップして補足を書いていきます。

nrfutil

 公式ページはこちら
 https://github.com/NordicSemiconductor/pc-nrfutil
 Mac/Linuxではpythonベースでインストールします。(公式ページに記載)
 Windows向けにはビルド済みバイナリが提供されています。以下からダウンロード
 https://github.com/NordicSemiconductor/pc-nrfutil/releases

μECC

 μECCはmake環境のみ入っています。Windowsでのビルド手順は以下の通り。

 以下をインストールします。
- Git for Windows ※gitを使っていれば入ってるはず
- make for Windows (http://gnuwin32.sourceforge.net/packages/make.htm) ※CygwinでもOK
- GNU Arm Embedded Toolchain Version 7-2018-q2-update (https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads/7-2018-q2-update)

※gitとmakeはパスを通しておきます。
※gccのバージョンは (SDK)/components/toolchain/gcc/Makefile.windows)に書いてあるので、それでググれば辿り着きます。

GNU_INSTALL_ROOT := C:/Program Files (x86)/GNU Tools ARM Embedded/7 2018-q2-update/bin/
GNU_VERSION := 7.3.1
GNU_PREFIX := arm-none-eabi

 準備が出来たら、(SDK)/external/micro-ecc/ でコマンドプロンプトを開き、build_all.batを実行します。
 (SDK)/external/micro-ecc/nrf52hf_armgcc/armgcc/micro_ecc_lib_nrf52.a が生成されていたらOK。

Bootloader

 前回の記事で書いたように、サンプルプロジェクト(/examples/dfu/secure_bootloader)を作業ディレクトリにコピーします。プロジェクトファイルは、pca10056_ble/ses を使用します。

秘密鍵/公開鍵のファイル

 private.key/dfu_public_key.c はプロジェクト外で管理し、公開リポジトリにはアップロードしないようにします。SES上で適宜参照先を変更しておきます。

Applicationの実装

 同様にして、サンプルプロジェクトからコピーします。(/examples/ble_peripheral/ble_app_buttonless_dfu)

出来ているものがこちらに

 Githubに、今回使ったすぐ焼けるプロジェクトファイル一式を載せておきました。
 https://github.com/jiro-aqua/nrf52-ota-example

  • プロジェクト外の ../dfu/にprivate.keyとdfu_public_key.cをコピーしてください。
  • sesでアプリケーションとブートローダーを開き、Releaseビルドしておきます。
  • package/配下でコマンドプロンプトを開き、package.batを実行すると、ROM焼き用イメージファイルとOTA用のイメージファイルが作成できます。

デバッグする時のための補足

 このApplicationとBootloaderにはちょっとした仕組みが入っています。

  • bootloaderはapplicationのCRCチェックに成功しないとapplicationを起動しない。
  • applicationはbootloaderの存在を確認しないとエラーで止まる。

 このままだと、SESでのデバッグに支障が出るので、bootloaderのmain.cに細工をいれます。

main.c
int main(void)
{
    uint32_t ret_val;

    // Protect MBR and bootloader code from being overwritten.
    ret_val = nrf_bootloader_flash_protect(0, MBR_SIZE, false);
    APP_ERROR_CHECK(ret_val);
    ret_val = nrf_bootloader_flash_protect(BOOTLOADER_START_ADDR, BOOTLOADER_SIZE, false);
    APP_ERROR_CHECK(ret_val);

    (void) NRF_LOG_INIT(nrf_bootloader_dfu_timer_counter_get);
    NRF_LOG_DEFAULT_BACKENDS_INIT();

    NRF_LOG_INFO("Inside main");
#if ( DEBUG_BOOTLOADER == 0 )
    ret_val = nrf_bootloader_init(dfu_observer);
    APP_ERROR_CHECK(ret_val);
#endif
    // Either there was no DFU functionality enabled in this project or the DFU module detected
    // no ongoing DFU operation and found a valid main application.
    // Boot the main application.
    nrf_bootloader_app_start();

    // Should never be reached.
    NRF_LOG_INFO("After main");
}

 BootloaderのデバッグビルドではDEBUG_BOOTLOADER==1となるように設定しておき、デバッグビルドを実行した時はCRCチェックなしでApplicationが実行されるようにしておきます。(このため、デバッグビルドではOTAは動作しません)
 また、sesでアプリケーションを実行する時にソフトデバイスが書き込まれるのですが、この時にMBR上のBootloaderのアドレスがクリアされてしまうため、ソフトデバイスがロードされないように設定しておきます。

ROM焼き

 ROM焼き用のイメージは以下の手順で作成します。

nrfutil settings generate --family %FAMILY% --application %APP% --application-version 1 --bootloader-version 1 --bl-settings-version 1 Output\settings.hex
mergehex --merge %SOFTDEVICE% %BOOTLOADER% --output Output\SD_BL.hex
mergehex --merge Output\SD_BL.hex %APP% --output Output\SD_BL_APP.hex
mergehex --merge Output\SD_BL_APP.hex Output\settings.hex --output Output\all.hex

 nrfutilでアプリの設定ファイルを作り、Bootloader,SoftDevice,ApplicationのHEXとマージします。これを、以下のバッチファイルで流し込みます。

program.bat
nrfjprog --family NRF52 --eraseall
nrfjprog --family NRF52 --program Output/all.hex
nrfjprog --family NRF52 --reset

 ※エラーが出る場合は、Command Line Toolsの最新版をチェックしてください。
  https://www.nordicsemi.com/Software-and-Tools/Development-Tools/nRF-Command-Line-Tools/Download#infotabs
  nRFgoと一緒に入るファイルはバージョンがえらく古いです。

 起動したら Nordic_Buttonless というデバイス名が見えるようになります。
image.png

OTA

 nRF-Toolboxを使います。Nordicがアプリストアに置いてあるnRF-ConnectというアプリでもDFUできますが、独自デバイスを開発する以上スマートホンアプリも作ることになるので、nRF Toolboxを自前ビルドして使用することをお勧めします。

 IOS-nRF-Toolbox
 https://github.com/NordicSemiconductor/IOS-nRF-Toolbox
 Android-nRF-Toolbox
 https://github.com/NordicSemiconductor/Android-nRF-Toolbox

  • Output/ota_all.zip BL,SD,APP全部入りのイメージ
  • Output/ota_app.zip APPのみのイメージ(通常はこちらで充分)

 自分で自分の上書をして、再起動することを確認します。

Tips

AndroidのnRF-Toolboxでは、GoogleDriveに置いたzipファイルを認識しません。MIMETYPEを"*/*"にすると認識します。

DfuActivity.java
    private void openFileChooser() {
        final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.setType(mFileTypeTmp == DfuService.TYPE_AUTO ? /*DfuService.MIME_TYPE_ZIP*/ "*/*" : DfuService.MIME_TYPE_OCTET_STREAM);

さいごに

 駆け足ですが、OTA/ROM焼きのための環境構築について説明しました。ここら辺は量産・運用には欠かせないポイントだと思います。次回以降は、このOTAできる環境をベースに構築していきます。

7
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
13