2025年9月8日月曜日

ベアメタル上のメニューシステム

 


Arduino上のメニューシステム

Arduinoはベアメタル環境で動作します。つまりOSという仲介者が存在せず、ハードウェアを直接制御するプログラムが1つだけ実行される環境です。この環境では、PCのように複数のプログラムを同時に実行することはできません。メモリ全体を1つのプログラムが占有し、CPUも1つのloop()関数を延々と実行し続けます。

この制約により、メニューもアプリケーションも、それぞれが完全に独立した単一のプログラムとして存在します。メニューを表示している間はメニュープログラムだけが動作し、アプリケーションを実行している間はそのアプリケーションだけが動作します。プログラムを切り替えるには、現在のプログラムを完全に終了し、ブートローダーが次のプログラムをフラッシュメモリから読み込んで起動する必要があります。

ベアメタル環境では、実行中のプログラムを外部から制御する仕組みが存在しないため、プログラム自身が「次に何を起動するか」をフラッシュメモリに書き込む必要があります。この書き込みタイミングが極めて重要です。

起動直後のsetup()関数実行時は、システムが最も安定した状態にあります。フラッシュキャッシュは初期状態で、不整合が発生する可能性がありません。SRAMも静的初期化のみが完了した清潔な状態で、ヒープの断片化も起きていません。さらに割り込み処理も最小限しか有効になっておらず、複数の割り込みが競合してフラッシュ書き込みを妨害する危険性もありません。

一方、プログラム実行中や終了時にフラッシュ書き込みを行うと、様々なリスクが生じます。キャッシュの不整合により書き込みが正しく行われない可能性があり、ヒープの断片化によってメモリ確保に失敗するかもしれません。複数の割り込みが競合している状態では、フラッシュ書き込み中に別の処理が割り込んでデータが破損する危険性もあります。

システムの事前準備方式は、これらの技術的制約を踏まえた設計です。アプリケーションは起動直後の最も安全なタイミングで「次回はメニュープログラムを起動する」という情報をフラッシュに書き込みます。この後は通常通り動作し、終了時は単純にリセットするだけです。電源断や異常終了が発生しても、既に次回起動の設定は完了しているため、確実にメニューに戻ることができます。

ベアメタル環境特有の制約と、ハードウェアレベルの動作特性を理解した上で設計された事前準備方式は、単一プログラムしか実行できないArduino環境において、複数プログラムの切り替えを確実に実現する優れた解決策です。

1 件のコメント:

  1. Watchdog RebootとFlashAndRebootの重要な違い

    核心的な違いは、ファームウェア書き込みのタイミングと方法にあります。flashAndReboot()はプログラム実行中に新しいファームウェアを書き込もうとします。この関数は、LittleFSからファイルを開き、Update.begin()でアップデート処理を開始し、Update.writeStream()でデータを書き込み、Update.end()で完了させてからrp2040.reboot()で再起動します。問題は、これらの処理が実行中の環境で行われるため、メモリが汚れていたり、他の処理が動作中だと失敗する可能性があることです。

    一方、watchdog_reboot()は単純なハードウェアリセットです。watchdog_reboot(0, 0, 100)という1行でハードウェアウォッチドッグを起動するだけで、複雑な操作は一切ありません。

    事前準備方式でWatchdog Rebootが重要な理由は、Arduino-Picoブートローダーの巧妙な機能を活用できるからです。Update.end()を呼ぶと、準備されたファームウェアが「保留中」としてマークされます。ブートローダーは再起動のたびに保留中のファームウェアをチェックし、存在すればプログラム開始前にフラッシュに書き込みます。

    動作の仕組みは次のとおりです。setup()関数で環境がクリーンな時にUpdate.begin()、Update.writeStream()、Update.end()を順に実行してメニューファームウェアを準備し、ブートローダーに「保留中」とマークします。その後、loop()関数でボタンが押されたら、watchdog_reboot(0, 0, 100)を呼ぶだけで再起動します。どんな再起動でも、ブートローダーが保留中のファームウェアを検出して自動的に適用します。

    この方式が優れている理由は複数あります。電源断への耐性があり、電源が切れても保留中のファームウェアは残っています。プログラムがクラッシュしてウォッチドッグが作動しても、メニューがロードされます。ボタン操作の信頼性も高く、単純な再起動なのでファイル操作による失敗がありません。さらに、setup()での準備は他に何も動作していないクリーンな環境で行われます。

    RP2350のブートローダーは起動のたびに次の処理を実行します。まずUpdate.end()が呼ばれたかを確認し、保留フラグをチェックします。フラグがあれば準備されたファームウェアをフラッシュに書き込み、保留フラグをクリアして新しいプログラムを開始します。これにより、電源OFF/ONでメニューに戻り、保留ファームウェアが残存します。ウォッチドッグタイムアウトでもメニューに戻り、単なる再起動として処理されます。ボタン押下でもメニューに戻り、watchdog_rebootが同じ経路を起動します。

    watchdog_reboot()が重要な理由は、ブートローダーの保留ファームウェアチェックを起動する確実でクリーンな再起動を提供するからです。事前準備と組み合わせることで、プログラムがどのように終了しても確実にメニューに戻る堅牢なシステムが実現されます。この設計により、ベアメタル環境での複雑なファームウェア切り替えが、シンプルかつ確実に動作するようになっています。

    返信削除