0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Raspberry Pi PicoのファームウェアをSDカードから起動する

Posted at

Raspberry Pi PicoのファームウェアをSDカードから更新したかったので、stage3のブートローダーを書きました。SDカードを読み書きできる環境があれば、PC無しでPicoのファームウェアを更新して回れるので便利。ただしPicoにはmicro SDカードスロットが備わっているものとする。

SDカードブートローダーの動作

このブートローダーは次のように動作します。

  1. SDカードをファイルシステム /sdにマウントする
  2. /sd/firmware.binとフラッシュのアプリケーション領域とを比較し更新の有無をチェックする
  3. 更新がある場合/sd/firmware.binをフラッシュのアプリケーション領域に書き込む
  4. フラッシュに書き込んだアプリケーション領域を実行する

つまりSDカードのファームウェアを直接実行するわけではなく、フラッシュメモリーにコピーしてから実行しています。

SDカードのマウント

FATファイルシステムとSDカードの操作にはPico用に開発したバーチャルファイルシステム pico-vfs を使用します。

公式のPicoおよびPico WにはSDカードソケットは装備されていないので、Adafruit MicroSD card breakout board+などを接続するか、筆者のようにPicoサイズのmicro SDカード付きプリント基板を貼り付けるなどして追加します。

pico-vfsを使うと、SDカードを接続したSPIのピン配置やボーレートなどを指定してブロックデバイスを定義し、定義したデバイスを使用するFATファイルシステムのマウントポイント(/sd)を指定するだけで、POSIX互換のファイル操作APIが利用できるようになります。

blockdevice_t *sd = blockdevice_sd_create(spi0,
                                          PICO_DEFAULT_SPI_TX_PIN,
                                          PICO_DEFAULT_SPI_RX_PIN,
                                          PICO_DEFAULT_SPI_SCK_PIN,
                                          PICO_DEFAULT_SPI_CSN_PIN,
                                          125000000 / 2 / 4,  // 15.6MHz
                                          true);  // enable CRC check
filesystem_t *fat = filesystem_fat_create();
fs_mount("/sd", fat, sd);

ファームウェアの更新検知と書き込み

ファームウェア/sd/firmware.binfopen()し、フラッシュに展開ずみの既存のファームウェアとmemcmp()で比較します。

static bool is_same_existing_program(FILE *fp) {
    uint8_t buffer[FLASH_SECTOR_SIZE] = {0};
    size_t program_size = 0;
    size_t len = 0;
    while ((len = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
        uint8_t *flash = (uint8_t *)(XIP_BASE + SD_BOOT_FLASH_OFFSET + program_size);
        if (memcmp(buffer, flash, len) != 0)
            return false;
        program_size += len;
    }
    return true;
}

SD_BOOT_FLASH_OFFSETがブートローダーを避けるための、256KBのオフセットです。
書き込みは、普通にflash_range_erase()してflash_range_program()するだけなので割愛。

アプリケーション領域の実行

フラッシュに書き込まれたアプリケーションの位置を指定して処理をブランチさせます。

void launch_application_from(uint32_t *app_location) {
    // https://vanhunteradams.com/Pico/Bootloader/Bootloader.html
    uint32_t *new_vector_table = app_location;
    volatile uint32_t *vtor = (uint32_t *)(PPB_BASE + M0PLUS_VTOR_OFFSET);
    *vtor = (uint32_t)new_vector_table;
    asm volatile (
        "msr msp, %0\n"
        "bx %1\n"
        :
        : "r" (new_vector_table[0]), "r" (new_vector_table[1])
        : );
}

SDカードブート用アプリケーションのビルドとデプロイ

ブートローダーからロードされるファームウェアは通常のRaspberry Pi Pico用ファームウェアと同じ書き方をしますが、CMakeLists.txtでenable_sdcard_app(TARGET)を指定することで、SDカード配布用ファームウェアとしてビルドできます。

CMakeLists.txt
cmake_minimum_required(VERSION 3.13...3.27)
include(vendor/pico_sdk_import.cmake)
add_subdirectory(pico-sdcard-boot)

project(hello)
set(FAMILY rp2040)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
pico_sdk_init()

add_executable(hello main.c)
target_link_libraries(hello PRIVATE pico_stdlib)
pico_enable_stdio_usb(hello 1)
pico_add_extra_outputs(hello)

enable_sdcard_app(hello)

enable_sdcard_app()関数は、SDカード配布ファームウェア用のリンカースクリプトを使用する手続きをカプセル化したものです。通常のリンカースクリプトと異なり、フラッシュの先頭から256KBオフセットした位置にファームウェアを配置するよう指示しています。また通常のstage2ブートローダーを省略しています。

開発からデプロイまでの手順を俯瞰すると、開発時は通常のPico用ファームウェアと同じ手順でデバッグ・動作確認を行います。実装が固まりデプロイする段になったならばenable_sdcard_app()を有効にしてデプロイ用.binファイルをビルドする流れになります。
ビルドされる.binファイルをSDカードのルートディレクトリにfirmware.binの名前で配置します。ファームウェアを含むSDカードを装着した状態でPicoを起動すれば、ブートローダーが新しいファームウェアをフラッシュにコピーして実行してくれます。

SDカードでファームウェアを更新する意義

筐体や設置場所の事情でPCとUSB接続が難しい場合や、開発者ではないエンドユーザーにファームウェア更新を依頼する場面を想定しています。通常の「BOOTSELボタンを押しながらPCにUSB接続して.uf2ファイルをドロップ」も十分シンプルな手順なのですが、これをもう一段シンプルな「SDカードをソケットに差し込んでスイッチオン」にできます。
実装にあたって参考にしたCustom Serial Bootloader for the RP2040ではUARTのシリアル通信でファームウェアを更新するブートローダーを作っています。今回ファームウェアを配布する媒体としてSDカードを使用しましたが、無線接続できるRaspberry Pi Pico WならOver-The-Airアップデートも割と簡単に実装できますね。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?