picotool
1 はもっぱらファームウェア書き込みツールとして利用されることが多い、Raspberry Pi Pico 公式ツールですが、ファームウェア書き込みだけでなくフラッシュメモリの任意の領域のデータを読み書きする機能を備えています。これを使えば「設定だけ後から書き換える」運用ができます。
設定を書き換えられると何がうれしいのか?
pico-examples2などもそうなのですが、ホビー向けのサンプルプログラムではWi-FiのSSIDやパスワードなどの設定をソースコードベタ書きでファームウェアに埋め込んでいる例が多いです。そのため、デバイスを別の場所で使う場面などでWi-Fiの設定を変更するには、ソースコードからビルドしなおす必要がありけっこう面倒です。ファームウェアとは別に設定情報だけ書き換えられるなら、デバイスの運用はずっとラクになります。
設定情報を書き込む手順
例えば、Picoのオンボードフラッシュメモリを以下のようなレイアウトで利用します。
アドレス | 内容 |
---|---|
0x10000000〜 | ファームウェア |
0x10100000〜 | 設定情報 |
1. 設定ファイル setting.txt
を用意する
ホストPCで、設定ファイル setting.txt
を作成します。
MySSID
MyPassword
プレーンテキストで記述し、行末の改行(\n
)を忘れずに。
2. 設定ファイルをフラッシュメモリへ書き込む
picotool load -o 0x10100000 -t bin setting.txt
この例ではpicotool load
コマンドに-o
オプションを付与し、フラッシュメモリの先頭(0x10000000)から1MBオフセットした位置(0x10100000)に設定情報を書き込みます。-t
オプションで拡張子を無視しバイナリーファイルとしてロードします。
⚠️ アドレスがファームウェア領域と重複しないよう注意してください。 設定情報を書き込む位置は、ファームウェアのサイズに応じて調整してください。
設定情報をデバイスで読み込む(C: pico-sdk)
デバイスでは設定情報を以下のように読み込みます:
#include <pico/stdlib.h>
#include <stdio.h>
#define SETTING_LOCATION _u(0x10100000)
typedef struct {
char ssid[32 + 1];
char password[63 + 1];
} wifi_setting_t;
// srcバッファの'\n'で終端された文字列をdestバッファにコピー
static uint8_t *load_string(char *dest, size_t maxlen, const uint8_t *src) {
uint8_t *end = (uint8_t *)src;
while (*end && *end != '\n')
end++;
size_t len = end - src;
if (len >= maxlen)
len = maxlen - 1;
memcpy(dest, src, len);
dest[len] = '\0';
if (len > 0 && dest[len - 1] == '\r')
dest[len - 1] = '\0';
return *end ? end + 1 : end;
}
// Flashから設定情報を読み込む
void load_settings(wifi_setting_t *setting, uint32_t offset) {
uint8_t *flash = (uint8_t *)offset;
flash = load_string(setting->ssid, sizeof(setting->ssid), flash);
load_string(setting->password, sizeof(setting->password), flash);
}
int main() {
wifi_setting_t setting;
printf("Load Wi-Fi setting from Flash\n");
load_settings(&setting, SETTING_LOCATION);
printf("Setting: SSID=%s, password=%s\n", setting.ssid, setting.password);
return 0;
}
実行時に XIP_BASE
(0x10000000
)から1MB離れた位置のバッファを、load_settings関数で読み込むだけです。オンボードフラッシュメモリの参照に特別なAPIは必要ありません。
応用: 設定情報を構造体バイナリとしてパックする
より複雑な設定情報を構成したい場合は、構造体にパックしたバイナリを書き込む方法もあります。Pythonなどで setting.bin
を作成:
import struct
ssid = "MySSID"
password = "MyPassword"
with open("setting.bin", "wb") as f:
f.write(struct.pack("33s64s", ssid.encode(), password.encode()))
同様にpicotool
でフラッシュメモリに書き込めば、 wifi_setting_t *
にキャストするだけで利用可能です。
補足: Pico2(RP2350)はパーテーションが利用できる
RP2350を搭載したPico2はパーテーションテーブルをサポートしています。一つのフラッシュメモリを「ファームウェア用パーテーション、設定データ用パーテーション」など複数の論理的領域に分割できるので、領域ごとの用途がより明確になります。RP2350環境で設定データをフラッシュメモリに埋め込む場合はパーテーションの利用も検討してみると良いでしょう。
まとめ:picotool はファームウェアだけじゃない
- picotool の
-o
オプションでフラッシュメモリの任意アドレスにデータ書き込み可能 - 設定を分離することで、運用が圧倒的に楽になる
- 同一ファームウェアで複数構成・複数環境に対応できる
Raspberry Pi Pico を使った小規模な組み込み開発でも、こうした工夫ひとつで運用がずっと楽になります。この例では\n
区切りのプレーンテキストで設定を記述しましたが、もう少し踏み込んでJSONや.INIといった構造化テキストを書き込んで、パースして利用する方式を取ることもできます。
picotool はファームウェア書き込みだけのツールではありません。「Pico用の汎用フラッシュメモリーライター」としての活用方法をぜひ試してみてください。