Raspberry Pi pico 解析(bootrom)

1 0
Raspberry Pi pico(以後 RPi-pico)のMPUであるRP2040は内蔵ROM:16KByte, 内蔵SRAM:264KByteを持っています。内蔵ROMはあくまでも起動用で書き込み不可、メインのプログラムはQSPIで繋げた外付けのFlashを使用する構成です。Cortex-M0+ なのに Cortex-A クラスの様な生意気な構成ですね。こういった構成の場合、内蔵ROMの中に普段使い慣れたような配置のプログラムが書かれていて、それが外付けFlashにアクセスして起動するのです。RP2040もそういった構成。なので、内蔵ROMに書かれたブートローダーの仕様に合わせて外付けFlashにFirmwareを書き込む必要があります。uf2形式で書き込むときも考え方は同じです。

rpi_nano_bus.png

通常内蔵ROMの仕様は小出しか全く隠蔽されているかなのですが、RPi-picoのすごいところは、ブートローダーのソースコードが丸々公開されています。なので、詳細を確認したい人はソースコードを追っかけてみてください。ここではRP2040 Datasheetに書かれている内容とブートローダーのソースコード(少し)を紐解いた内容をもとに電源ONからユーザーが書き込んだプログラムにたどり着くまでどのような動作をするのかを記載します(前もって言っておきますが内容は薄いです)。

こんな感じです。

rpi_pico_boot_sc.png

②は正確には 2nd stage で行うのでここで記載しているブートローダーの仕事では無いですが、C/C++ SDKの構成ではこうなっているよという意味で描いてみました。

RP2040は電源ON直後に0x00000004番地(内蔵ROM)のリセットベクターを参照してブートローダーを実行します。ブートローダーの仕事は主に2つ。外部Flashから内容を読みだしてSRAMにコピーしてジャンプする事と、USB-MSCによって.uf2ファイルを書き込む事。後者は説明を省きます。前者を大雑把に書くと以下の内容です。

1. SPIモードで外部Flashの先頭256byteを内蔵SRAMのRAM5の末尾256byteにコピーする
2. CRC32チェックする
3. コピーした先へジャンプする

RP2040 Datasheetのフローではこうなってます。
(ブートローダーは processer core 0 のみで動いています)

rpi_pico_bootrom_sc.png

内蔵SRAMは0~5まであって、0~3はちょいと複雑な構成になってますが、SRAM4,5はこんな感じにそのまま配置されてます。

rpi_pico_sram45_addr.png

これより、SRAM5は0x20041000~0x20041FFFということが分かりますね。これの末尾256byteですから…。0x20041F00~0x20041FFFにコピーされます。これはC/C++ SDKのリンカスクリプト(pico-sdk/src/rp2_common/boot_stage2/boot_stage2.ld)からも明らかですね。C/C++ SDKではこの後に 2nd stage としてXIP機能を有効にしてQSPIの領域をメモリマップドの様に扱える設定をしています(実際はQSPIの命令が飛び交っています)。ブートローダーではベクター領域の設定をそのままにしてジャンプするだけなので、2nd stage でベクター領域を置き換えています。

ブートローダーの仕様からその後に用意しなければならないことは以下になりそうです。

1. 先頭からプログラムを記載する(ベクター領域ではなく動く部分です)
2. 252byteでプログラムを完結させるかXIPの設定をしてジャンプするかを行う
3. ベクター領域を再設定する
4. processer core 1 を起動させる?

1~3はC/C++ SDKを推奨仕様のまま使用される場合はSDK内で自動的に生成される部分です。
ページトップ