省RAM型BootLoaderとは
省RAM型BootLoaderは、外部メモリを使わずにファームウェア更新を完結させる方式である。 更新イメージはアプリケーションフラッシュ領域に直接書き込むため、RAM や外部ストレージを追加する必要がない。 一方で、更新失敗時にアプリケーションが消失するリスクがあり、失敗検知とリカバリ機構が必須となる。
省RAM型と二領域型の比較
| 観点 | 省RAM型(本設計) | 二領域型 |
|---|---|---|
| 追加メモリ | 不要 | 更新領域が必要 |
| 更新時間 | 短い(直接書き込み) | 長い(コピー工程あり) |
| 失敗時の挙動 | BootLoaderのみ起動 | 旧アプリで動作継続 |
| BootLoaderサイズ | 大きい(更新ロジック内包) | 小さい(コピーのみ) |
コア機構
1. ジャンプ制御
アプリ ↔ BootLoader 間のジャンプはベクタテーブルを関数ポインタとして呼び出す。 Cortexでは次のように記述する(Cortex-M 系を想定)。
/* ジャンプ先アドレス(VTOR + 4 = Reset_Handler) */
constexpr uintptr_t APP_RESET_VTOR = 0x0800'8000UL + 4U;
using ResetFunc = void(*)();
void invoke_app()
{
uint32_t reset_addr = *reinterpret_cast<uint32_t*>(APP_RESET_VTOR);
ResetFunc jump = reinterpret_cast<ResetFunc>(reset_addr);
/* 割り込み無効化・クロック初期化等を省略 */
jump(); /* アプリへジャンプ */
}
2. 上位機(SOC)の電源維持
SOC の電源EN端子を MCU のGPIOで制御している場合、BootLoader では当該GPIOを Hi-Z にして初期化をスキップする。 これにより SOC がリセットされず、USB/UART 等の通信路が維持される。
3. 更新失敗検知
フラッシュ最終セクタに 32-bit ステータスワードを配置し、以下の状態を表現する。
- 0xAAAAAAAA : 更新開始
- 0x55555555 : 更新成功
- 0xFFFFFFFF : 初期値(未更新/出荷状態)
- その他 : 更新失敗
起動時にこのワードを読み、0x55555555 の場合のみアプリへジャンプする。 更新中に電源断が発生しても、次回起動時に BootLoader が検知し再更新を促す。
実装時の落とし穴
1. 誤リセット問題
BootLoader 内で FTM タイマを初期化する際、EXTTRIG.INITTRIGEN ビットを 1 にしていたところ、CNTIN 一致でタイマリセットが発生し、ウォッチドッグへのパットが遅延して MCU がリセットする事象が発生した。 対策として、INITTRIGEN を無効化し、CNTIN 一致割り込みを使用しない構成に変更した。
2. フラッシュ書き込み失敗
アプリ実行中にフラッシュを消去/書き込みしようとすると失敗するケースがあった。 原因は MCU が HSRUN モード(高周波)で動作しており、フラッシュタイミングが合わないため。 RUN モードにダウンスケールしてからフラッシュ操作を行い、完了後に再び HSRUN へ移行することで解決した。
void write_status_word(uint32_t value)
{
enter_run_mode(); /* HSRUN → RUN */
flash_unlock();
flash_erase_page(STATUS_PAGE);
flash_program_word(STATUS_ADDR, value);
flash_lock();
enter_hsrun_mode(); /* RUN → HSRUN */
}
まとめ
省RAM型BootLoaderは、リソース制約の厳しい組み込み機器において最小構成で OTA 更新を実現できる。 更新失敗時の安全性は犠牲になるが、フラグ管理とジャンプ制御を工夫することで、実用上十分な信頼性を確保できる。