nRF52のDFU試験1

# 概要
NordicのBLEモジュールnRF52のファームウェアを、アプリを使用して無線で更新（OTA）します。
Nordicでは、この機能はDFU(Device Firmware Update）という名称で呼ばれています。


# 参照
本記事は以下の内容を参照しました。

[nrf52でOTAする(Secure Bootloader+DFU)](https://qiita.com/chabose/items/dab0b12f460f85918c8d)

[nRF52でBLEデバイスを開発する（２）OTAアップデート Buttonless DFUとSecure DFU](https://qiita.com/jiro-aqua/items/97c8ec6910d584281b7a)

# 環境
- OS
    - Windows 10
- ソフト：
    - Cygwin
    - Anaconda3
    - SES
- SDK
    - 16.0.0
- Softdevice
    - s140_nrf52_7.0.1
- BLEモジュール
    - nRF52840

今回はBLEモジュールにはnRF52840を使用しました。
他のBLEモジュールを使用する場合は、Softdeviceを対応するものに変更してください。

# 準備
nRF52の開発環境は構築済みとします。
以下をご参照ください。
[Nordic社製BLEの開発環境構築と動作確認](https://qiita.com/Kosuke_Matsui/items/5d61ce77e928b9f117cc)

## μECCのインストール
Cygwin上で作業します。
micro-eccフォルダに移動して、build_all.batを実行します。

```
$ cd nRF5SDK160098a08e2/external/micro-ecc/
$ ./build_all.bat
```

nRF5SDK160098a08e2は私のSDKフォルダの名前です。
各位の環境に合わせて名前を変更してください。

ここでビルドエラーになる場合は、gccツールのバージョンが不適切な場合があります。
私の場合は、エラーメッセージに2019-q4がないとありました。
そこで以下から「gcc-arm-none-eabi-9-2019-q4-major-win32.exe」をダウンロードして実行しました。

https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads

![gccダウンロード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150620/05ffa6be-9174-ad6d-272c-2e4100a027f3.png)

gccツールをインストール後はビルドに成功し、nRF5SDK160098a08e2\external\micro-ecc\nrf52hf_armgcc\armgcc に micro_ecc_lib_nrf52.aが生成されました。

## nrfutilのインストール

Anaconda3上で作業します。
nrfutilをインストールします。

参照した記事ではpython2でないとnrfutilを実行できないとありましたが、python3でも実行できるようになっていました。

```
$ pip install nrfutil
```

# 秘密鍵・公開鍵のペア作成
Anaconda3上で以下のコマンドを実行すると、dfu_public_key.cファイルが作成されます。

```
$ nrfutil keys generate private.key
$ nrfutil keys display --key pk --format code private.key --out_file dfu_public_key.c
```

dfu_public_key.cファイルをnRF5SDK160098a08e2/examples/dfu/に移動します。

# サンプルプログラム、セキュアブートプログラムのビルド
SESにおいて作業します。
nRF52840に対応したサンプルプログラムを開きます。

nRF5SDK160098a08e2\examples\dfu\secure_bootloader\pca10056_s140_ble\ses\secure_bootloader_ble_s140_pca10056.emProject

もしnRF52832を使用しているならば以下を開いてください。

nRF5SDK160098a08e2\examples\dfu\secure_bootloader\pca10040_s132_ble\ses\secure_bootloader_ble_s132_pca10040.emProject

sdk_config.hのNRF_DFU_HW_VERSIONを任意の数字に変更してからビルドします。

![HW_Version.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150620/b3879e95-b7ea-0b7c-1441-fa12820c5839.png)

ビルドに成功すると
nRF5SDK160098a08e2\examples\dfu\secure_bootloader_test\pca10056_s140_ble\ses\Output\Release\Exeにsecure_bootloader_ble_s140_pca10056.hexが生成されます。

## 書き込み
nRF ConnectでSoftdeviceとsecure_bootloader_ble_s140_pca10056.hexを書き込みます

![書き込み.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150620/a17db013-24df-a6c2-7680-69423d1b567f.png)

ソフトデバイスが書き込み済みならばSES上からも書き込みできます。（ご要望があれば、書き込み方法の記事を作成するのでコメント欄にコメントください。）

# サンプルプログラムのビルド

DFUによって書き込むサンプルプログラムもビルドします。
ble_peripheralフォルダのサンプルプログラムならば何でもいいので、適当に選んでください。
本記事では、以下を開いてビルドしました。

nRF5SDK160098a08e2\examples\ble_peripheral\ble_app_hrs\pca10056\s140\ses\ble_app_hrs_pca10056_s140.emProject

ビルドに成功すると
nRF5SDK160098a08e2\examples\ble_peripheral\ble_app_hrs\pca10056\s140\ses\Output\Release\Exeにble_app_hrs_pca10056_s140.hexが生成されます。


# zipファイル作成

## SoftDeviceのバージョンの確認

ソフトデバイスのバージョン番号を確認します。
Anaconda3上で以下のコマンドを実行します。

```
nrfutil pkg generate --help
```

すると以下のようにソフトデバイスの番号が表示されます。
![ソフトデバイス番号.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150620/7b0f1b6b-866c-bb78-3b73-f3a01bf9eb29.png)

今回使用しているのはs140_nrf52_7.0.1なので、番号は0xCAになります。

## 署名
Anaconda3上で以下のコマンドを実行してzipファイルを生成します。
ble_app_hrs_pca10056_s140.hexファイルをnrfutilを実行するフォルダに移動します。

```
nrfutil pkg generate --hw-version 1 --application-version 1 --application ble_app_hrs_pca10056_s140.hex --sd-req 0xCA --key-file ./private.key  hrs_application_s140.zip
```


hw-versionはNRF_DFU_HW_VERSIONで設定した数字を使用します。
先ほどにNRF_DFU_HW_VERSIONを1にしていたので、ここでも1にします。

sd-reqは先ほど調べた0xCAを使用します。




# DFU実行

今回はiPhoneでDFUを実行します。
アプリnRF ToolBoxをインストールしてください。

nRF ToolBoxを実行して、DFUをタップします。

![IMG_2068.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150620/8de4852f-c950-34ab-5d2f-8c2973bea4f1.png)

CONNECTでBLE接続します

![IMG_2069.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150620/b4482a35-a39a-68dc-c3cc-b16d9a410c72.png)


DfuTargを選択します

![IMG_2070.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150620/ffaab9af-707a-d0aa-fa50-de2e2d5a8081.png)

Borwseをタップします。

![IMG_2071.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150620/8104d1d9-d4ee-5cee-bb51-fdf14f1b590d.png)

zip化したファイルをiCloudにuploadしておき、それを選択します。

![IMG_2073.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150620/1a0aa4ee-3897-e624-ec13-3d7ea628b9c7.png)

updateをタップします。

![IMG_2075.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150620/efc0ede0-c15c-d77b-c78c-afaa0ff44574.png)

updateに成功すると以下の画面になります。

![IMG_2076.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150620/9b7fb687-41f8-977d-ea50-a8af2dd57a54.png)


## エラーが出る場合

NRF_DFU_HW_VERSIONが一致しないと、アプリ上に"HW version checked failed"というエラーメッセージが表示されます。

例えば、先ほどにzipファイルを生成するときにNRF_DFU_HW_VERSIONと異なる数字を設定するとこのエラーになります。

```
$ nrfutil pkg generate --hw-version 99 --application-version 1 --application ble_app_hrs_pca10056_s140.hex --sd-req 0xCA --key-file ./private.key  hrs_application_s140.zip
```

ソフトデバイス番号が正しくないと、アプリ上に"SD version checked failed"というエラーメッセージが表示されます。

![IMG_2074.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150620/cda11fa9-e1e4-63c4-1005-af17acbbd8b1.png)


例えば、先ほどにzipファイルを生成するときに使用しているソフトデバイスと異なる数字を設定するとこのエラーになります。

```
$ nrfutil pkg generate --hw-version 1 --application-version 1 --application ble_app_hrs_pca10056_s140.hex --sd-req 0xA8 --key-file ./private.key  hrs_application_s140.zip
```

# 次にすること
以上の方法では、一度ファームウェア更新すると、２度と同じようにDFUできなくなります。
何故なら、書き込んだサンプルプログラムble_app_hrs_pca10056_s140.hexにはセキュアブート機能がないからです。

一度しか無線で更新できないのでは実用性はありません。
何度でもDFUしたければ、書き込んだサンプルプログラムにもセキュアブート機能を移植しないといけません。

次はそれをしてみたく思います。

また、今回はアプリを使用しての更新でしたが、サーバを介しての自動更新もしてみたいところです。

他にも自由に使用できるメモリ半分になってしまう問題など多くの課題があるので、それらに対してどのように対応すべきか検討していく予定です