■ファームウエア更新
前回は組込機器の機能を実現するユーザアプリケーションについて書きましたが、今回はユーザアプリケーションでありながらハードウエアにも深くかかわる面倒な機能「ファームウエア更新」について書こうと思います。私がこの世界に入った20年近く前では、組込機器にはまだネットワーク機能がなく、スタンドアロンで決まった動作をするものがほとんどでした。それなら、プログラムは製造時に一発焼いておしまい、市場でのファームウエア更新機能は不要、が普通です。しかしインターネットの普及からIoT時代となり、組込機器はネットワークという付加価値を手にしたと同時に、スタンドアロンではすまない不確実な環境で問題なく動き続ける必要が出てきました。しかも「脆弱性」という、どんなに対策しても100%安全といえない問題にも常に向き合い続けなければなりません。ネットワーク機能を持つ組込機器においてファームウエア更新の機能は今やかなり優先度の高い、必須機能となった、ということです。パソコンの世界なら、OS含めたソフトウエアはネットワーク経由で特定のサーバから最新ソフトウエアをダウンロードして更新する、のような便利な機能が用意されています。組込機器でもファームウエア開発段階ではデバッガ経由で更新ということが普通にできるので見落とされがちですが、組込機器を世の中にリリースした後どうやって更新するのかは案外面倒な話題です。具体的にはこのような議論ポイントがあるでしょうか。
・そもそもファームウエア更新は必要なのか?
・更新するのはサービスマンか?エンドユーザか?
・どのI/Fを使って新ファームウエアを入れるのか?
・旧ファームウエアへのロールバックはできるのか?許すのか?
・更新に失敗した場合、何が起きるのか、その後リカバーはどうするのか?
・更新実行者にどのような形で新ファームウエア、更新方法を伝えるのか?
これらの「?」への答えは会社の方針や機器の仕様に強く依存するため、ネットワークミドルウエアのように汎用パッケージとして売っているものではありません、ただ、環境を固定するとその環境向けのファームウエア更新機能が提供されるケースがあります。
たとえばCPUメーカがユーザアプリケーションに組み込むためのファームウエア更新プログラムを提供してくれたり、
RXファミリ ファームウェアアップデートモジュール
https://www.renesas.com/jp/ja/document/apn/rx-family-firmware-update-module-using-firmware-integration-technology-application-notes
ハード・ファーム・クラウドの全てをawsで揃えます、という方のためにawsはFreeRTOS向けのファームウエア更新プログラムを無償提供しています。
FreeRTOS 無線通信経由更新
https://docs.aws.amazon.com/ja_jp/freertos/latest/userguide/freertos-ota-dev.html
CPU選定の際にはこういった機能をどうするか、という視点も必要になる、ということです。
★Centeでは...
我々は製品にそのまま組み込んでお使いいただくことを想定した名刺サイズのCPU基板「ESPT」シリーズを開発・販売していましたが、前述の議論を経てESPT向けにファームウエア更新機能を提供していました。
CPU基板「ESPT」シリーズ
https://www.cente.jp/product/cente-hardware/
ファームウエア更新機能を含む、ブートストラッププログラム:ESPT2-Booter
https://www.cente.jp/product/cente-suite/espt2-sdk-espt2-booter/
Booterにおけるファームウエア更新機能は以下のような仕様で実現しています。
・Booterとユーザファームの2段構成
電源を入れたら最初に動くブートストラップをBooter、本来の組込機器の機能を実現するプログラムをユーザファームと呼んで、別々に扱うことにしました。Booterとユーザファームはフラッシュメモリ上の別のところに焼き込みます。Booterは書き換えずに固定として、ユーザファームのみ書き換えて運用します。
・Booterでの通常起動シーケンス
Booterではユーザファームが焼き込まれているフラッシュメモリの領域をチェックサムで正当性を確認します。正しければユーザファームをRAMにコピーしてその先頭にジャンプします。これが通常起動シーケンスです。
・Booterでのユーザファーム更新
前回ユーザファーム書き込み時に電源が落とされたなどフラッシュメモリ上のユーザファームが不正だったり、ダウンロードスイッチが押された状態でBooterを起動した場合、BooterはシリアルI/Fからのコマンド待ち状態になります。ここでファームウエア書き込みコマンドを送ったあとXMODEM(なつかしい!)でユーザファームを送ると新しいユーザファームに更新されます。
・ファームウエアへの一工夫
ESPTのファームウエアファイルにはビルドしてできるバイナリファイルの前にチェックサムの計算結果などを書き込んだ独自ヘッダ部分を追加していました。前述のユーザファームの正当性チェックに使用します。ビルド後に手動でやるのは面倒なので、そういうプログラムをexeにしておいて、ビルドシーケンスの最後に追加実行するようにしておきました。
なお、とあるお客様向けの受託案件においてこの構成を拡張し、ユーザファーム領域を2面持つようにしました。こうすることで、
・2面のうち、Ver.の新しい方のファームウエアが起動する
・ファームウエア更新時に古いVer.の方を上書きする
・途中で上書きに失敗しても、次回は従来のファームウエアで起動する
といったフェイルセーフ強化が実現できます。
・ネットワークブート機能
これまでのお話とちょっと違う機能ですが、Booterにはネットワークブート機能も入れました。
結局この仕組みにおいては、ビルド→シリアルで転送→フラッシュメモリに書き込み→ESPT再起動という操作が必要になります。でも開発時は、この操作を何度も繰り返すことになるのでできるだけ短い時間でやりたくなりますよね。その夢をかなえた機能になります。
具体的には、Booter起動時にネットワークブート機能が有効であれば、設定したTFTPサーバからファームウエアファイルを引っ張ってきて直接RAMに書いて先頭にジャンプします。ファームをビルドするPCにてTFTPサーバを起動しておいてそのホームディレクトリをビルド結果のファームウエアファイルができる場所に指定しておくと、以降エンジニアの操作はビルド→ESPT再起動だけでおしまいです!ネットワークが必須だったりフラッシュメモリには焼かれないという条件があるものの、これ以降この環境を利用した全てのファームウエア開発プロセスで相当開発効率を上げた機能でした。
一方、機器運用中にユーザがユーザファームを更新する機能もESPT向けアプリケーションファームウエアでご提供しました。
ESPT2-STD
https://www.cente.jp/product/cente-suite/espt2-std/
ESPT2-STDでは(当時ではまだ珍しかった)Webページでの管理方法を採用しており、「ファームウエア更新」のようなページで提供していました。内部的にはPCから受け取ったユーザファームファイルをフラッシュメモリに書き込むだけですが、CPUによってはRAMでプログラムを実行するよりフラッシュメモリ上でそのまま実行する方が効率が良い(実行速度が速い)場合があります。普通はフラッシュメモリで動いているプログラムからフラッシュメモリを書き換えることはできませんので、「ある領域のデータをフラッシュメモリに書き込む」というプログラムだけRAMにコピーして、そこにジャンプするような裏技を使ったりします。
前述の通り、ファームウエア更新プログラムは個々の組込機器の仕様に強く依存するためCenteでも汎用パッケージとしてご提供できていません。しかし、ノウハウとしては自社製品や受託案件でたんまり蓄積しております。「こういう環境でファームウエア更新機能を入れたいんだけど...」のようなざっくりとしたご希望でも、是非一度我々にお話をお聞かせください。
■今日の閑話
弊社でのインターンにおいて、私の「ファームウエア開発業務というお仕事」という講義の時間があります。そこでは最初に参加者にこんな質問をしています。みなさんが朝起きてから夜寝るまでの間いろんな電気製品を使っていると思います。では、その中でCPUが入って*いない*ものは何ですか?
これ、案外出てきません。なんとか「おじいちゃんの家にある扇風機」みたいな古い家電をひねり出すことになります。それだけ組込機器は身の回りに大量にあって、そのCPUの種類の数だけ我々のようなファームウエアを書いている人がいるんだよ、というお話をするためです。あぁ、そういえば一度だけ「枕」と即答して参加者全員の頭の上に「?」を並べたツワモノがいましたね...
Cente:
https://www.cente.jp/
お問合せはこちら:
https://www.cente.jp/otoiawase/