nRF Connect SDK:multi image buildとsysbuild

# multi image buildだと……？
今まであまり意識せずに記事を書いていましたし、そもそもmulti image buildとかparent/childとかいう言葉も使ったことがないのですが、nRF Connect SDKではアプリケーション部分がいわゆるParent(親)となり、それ以外の部分、一番よく知っているものだとブートローダーがChild(子)という構成のビルドイメージが該当します。他にもnRF53より上位シリーズのマルチコアもアプリケーションコアがParent(親)でネットワークコアがChild(子)という構成をしています。nRF53でBLEを使ってかつブートローダーを持つビルドだと子イメージが二つになります。
詳しい記事はこちらにあります。

https://academy.nordicsemi.com/courses/nrf-connect-sdk-intermediate/lessons/lesson-8-bootloaders-and-dfu-fota/topic/multi-image-builds-and-the-partition-manager/

このmulti image buildという方式がnRF Connect SDK 2.9.0以降は廃止され、代わりにnRF Connect SDK 2.5.0(たしか)から採用されているsysbuildという方式に完全に移行します。

::: note
ちなみに2.9.0-rc1ではまだ残っています(笑)
:::

## つまり2.5.0～2.8.0は移行期間
だったのですが、なにせ情報がなさすぎる上に今までのmulti image buildとは全然違うものになっているので、この間にちゃんと移行できた人なんてほとんどいないんじゃないでしょうか。上記のURLでもSDK 2.7.0とそれ未満で説明がタブ分けされていますが、この記事を書いている2024/12/16時点では2.7.0以上向けのほうはまだ記事ができておりません。

::: note
そもそもnRF Connect SDKをアクティブに使っている人が少ない説もｗ
:::

# child_imageフォルダってそういうことか！
(今さらmulti image buildのことを詳しく解説してもあまり意味がないのでちょっとだけ……)
ここまで理解して初めてプロジェクト内に生成するchild_imageフォルダの意味が分かったのではないでしょうか。そうです、これはchildイメージとして扱われるブートローダーやネットワークコアに対するKconfigだったんですね。その.confもchildイメージが複数あるときのためにそれぞれのイメージの名前になっているわけです。(例：mcuboot.conf)
これをちゃんと理解できていればブートローダーにプライベートキーを設定するのにあんなにも悪戦苦闘することもなかったわけですが……。
# sysbuild
sysbuildはプロジェクトにsysbuild用のコンフィギュレーションファイルであるsysbuild.confを追加してsysbuild用の設定を記述します。また、ブートローダーがなく、かつシングルコアMCU(nRF52840など)の場合はsysbuild.confで設定することがないのでファイルはなくてもよいです。

::: note warn
製品ではブートローダーがあったほうがよいのであまり考えにくいですが……。
:::

# sysbuildには専用のKconfigが存在する
まず最初の難関ですがsysbuildには専用のKconfigが存在しています。ただし、これはKconfig search
Kconfig search

https://docs.nordicsemi.com/bundle/ncs-latest/page/kconfig/index.html

では探すことができません。ではどこにあるのかというとこちらにあります。
Migrating from multi-image builds to sysbuild

https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/releases_and_maturity/migration/migration_sysbuild.html

もしくはこちらを辿ってもよいですが、先のURLのほうが理解しやすい気がします。
Configuring sysbuild

https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/app_dev/config_and_build/sysbuild/index.html

## nRF52840でブートローダーを実装してみる
ここまで色々と解説してきましたが、そんなことよりも実際に実装してみるほうが遥かに分かりやすいです。最初からそうしろよ、と言われるとその通りなのですが、実装コードだけ貼り付けても味気ないじゃないですか(笑)。
ということでnRF52840で実装していこうと思います。

``` sysbuild.conf
SB_CONFIG_BOOTLOADER_MCUBOOT=y
SB_CONFIG_SECURE_BOOT_APPCORE=y
SB_CONFIG_MCUBOOT_UPDATEABLE_IMAGES=1
SB_CONFIG_BOOT_SIGNATURE_TYPE_RSA=y
SB_CONFIG_BOOT_SIGNATURE_KEY_FILE="<Abusolute Path>/<Private Key File>"
```

え？nRF52840なのにRSAってどういうこと……と思った方はなかなか理解している人ですね(笑)。
特筆すべきは、multi image buildではシグネチャタイプが固定されていましたがsysbuildでは自分で選ぶことができます。具体的にはnRF52840はmulti image buildではECDSA256しか使えませんが、sysbuildではRSA2048も使うことができます。試してはいないのですが、同様にnRF5340(nRF7002)ではRSA2048固定ではなくECDSA256を使うこともできるはずです。
備忘録としてプライベートキーを生成するコマンドも載せておきます。
``` RSA.
python <ncs folder>\bootloader\mcuboot\scripts\imgtool.py keygen --type rsa-2048 --key priv_rsa.pem
```

``` ECDSA.
python <ncs folder>\bootloader\mcuboot\scripts\imgtool.py keygen --type ecdsa-p256 --key priv_ecdsa.pem
```


::: note
MCUによってシグネチャを使い分けないといけなかったのは地味にめんどくさかったんですよね。
:::

# そしてビルド
nRF Connect SDK 2.8.0以降はBuild system defaultで選択されるビルドがuse sysbuildになっていますので、Edit Build Configurationで何も変更せずにBuild Configurationボタンを押すだけです。

::: note
ていうか、そのうちこの設定自体が消えるよね(笑)
:::

ビルドした結果がこちらです。ちゃんとbuildフォルダの隣にsysbuildと記載があります。参考までに同一プロジェクトをno sysbuildでビルドした結果(build_nosys)も載せておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3797041/4de4c756-4059-5f4a-58ae-544897ae915f.png)

……え？
ちょっと待って？
そんなに簡単なの？

という質問には「シングルコアなので設定することが少なくて簡単」と回答しておきます。sysbuildのメインターゲットはnRF5340やnRF7002、そして最近出てきたnRF54系と思われ、それらを扱うにはここで説明した内容よりもぐっと複雑になります。
## ログメッセージ
ログメッセージを見てみるとmulti image buildの時とはちょっと違っているのが分かります。

```
*** Booting nRF Connect SDK v2.9.0-rc1-2dee59af02a1 ***
*** Using Zephyr OS v3.7.99-0a2e205750dc ***
Attempting to boot slot 0.
Attempting to boot from address 0x9200.
I: Trying to get Firmware version
I: Verifying signature against key 0.
I: Hash: 0x6c...3f
I: Firmware signature verified.
Firmware version 1
I: Setting monotonic counter (version: 1, slot: 0)
*** Booting MCUboot v2.1.0-dev-12e5ee106034 ***
*** Using nRF Connect SDK v2.9.0-rc1-2dee59af02a1 ***
*** Using Zephyr OS v3.7.99-0a2e205750dc ***
I: Starting bootloader
I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
I: Boot source: none
I: Image index: 0, Swap type: none
I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
I: Boot source: none
I: Image index: 1, Swap type: none
I: Bootloader chainload address offset: 0x21000
*** Booting nRF Connect SDK v2.9.0-rc1-2dee59af02a1 ***
*** Using Zephyr OS v3.7.99-0a2e205750dc ***
[00:00:00.000,671] <inf> bt_sdc_hci_driver: SoftDevice Controller build revision: 
                                            5e 89 40 59 db 09 d7 b7  04 e6 67 8d c1 e3 8c cc |^.@Y.... ..g.....
                                            0c e1 9c d3                                      |....             
[00:00:00.003,265] <inf> bt_hci_core: HW Platform: Nordic Semiconductor (0x0002)
[00:00:00.003,295] <inf> bt_hci_core: HW Variant: nRF52x (0x0002)
[00:00:00.003,326] <inf> bt_hci_core: Firmware: Standard Bluetooth controller (0x00) Version 94.16521 Build 3607747417
[00:00:00.004,241] <inf> bt_hci_core: Identity: D8:81:9A:E9:DF:2F (random)
[00:00:00.004,272] <inf> bt_hci_core: HCI: version 6.0 (0x0e) revision 0x1063, manufacturer 0x0059
[00:00:00.004,302] <inf> bt_hci_core: LMP: version 6.0 (0x0e) subver 0x1063
[00:00:00.005,249] <inf> ble: Advertising started.
```

ちなみにmulti image buildの場合はこちらになります。ブートローダー部分のログが異なりますね。ブートアドレスなども異なるようですがこのあたりは自動で決まっているようです。

```
*** Booting MCUboot v2.1.0-dev-12e5ee106034 ***
*** Using nRF Connect SDK v2.9.0-rc1-2dee59af02a1 ***
*** Using Zephyr OS v3.7.99-0a2e205750dc ***
I: Starting bootloader
I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
I: Boot source: none
I: Image index: 0, Swap type: none
I: Bootloader chainload address offset: 0xc000
*** Booting nRF Connect SDK v2.9.0-rc1-2dee59af02a1 ***
*** Using Zephyr OS v3.7.99-0a2e205750dc ***
[00:00:00.000,671] <inf> bt_sdc_hci_driver: SoftDevice Controller build revision: 
                                            5e 89 40 59 db 09 d7 b7  04 e6 67 8d c1 e3 8c cc |^.@Y.... ..g.....
                                            0c e1 9c d3                                      |....             
[00:00:00.003,295] <inf> bt_hci_core: HW Platform: Nordic Semiconductor (0x0002)
[00:00:00.003,326] <inf> bt_hci_core: HW Variant: nRF52x (0x0002)
[00:00:00.003,326] <inf> bt_hci_core: Firmware: Standard Bluetooth controller (0x00) Version 94.16521 Build 3607747417
[00:00:00.004,241] <inf> bt_hci_core: Identity: D8:81:9A:E9:DF:2F (random)
[00:00:00.004,272] <inf> bt_hci_core: HCI: version 6.0 (0x0e) revision 0x1063, manufacturer 0x0059
[00:00:00.004,302] <inf> bt_hci_core: LMP: version 6.0 (0x0e) subver 0x1063
[00:00:00.005,279] <inf> ble: Advertising started.
```

# 感想
思っていたよりはずっと簡単でした。
正直、multi image build時代のchild_imageの扱い方のほうが意味が分かりませんでした(笑)。
マルチコアのsysbuildは別途記事を書きたいと思います。

::: note warn
特にnRF7002はドハマりします(笑)
:::