/home/tnishinaga/TechMEMO

日々行ったこと、面白かったことを書き留めます。

Raspberry Pi 5のRP1に搭載されているPIOは今のところ簡単には使えないという話

私が海外でPi5発売されてから楽しみにしていたことの一つは「RP1に搭載されているPIOが使えるか」です。

画像は https://datasheets.raspberrypi.com/rp1/rp1-peripherals.pdf のFigure2,pp.6 より引用(一部加筆)

海外でのPi5発売とほぼ同時期に公開されたRP1のマニュアルをみると、Cortex-M3コアにPIOが接続されている様子が示されていました。 また、同マニュアルのpp.12よりRP1のコアクロックは200MHzらしいです。 (PicoのRP2040と同じなら)PIOはコアクロックと同じ速度で動くはずなので、理論値で最大100MHzくらいの信号を出力できるかもしれず、ワクワクしていました。

時が経ち2024年2月13日、ついにPi5が日本でも発売され、嬉しいことに1台購入することができました。 そこで早速RP1のPIOを使う方法を調べてみたのですが、どうやら今のところ使えなさそうとわかりました。

以下、調べたことをつらつらと書いていきます。

(PIOについては手前味噌ですが こちらの資料 をご参照ください)

なぜPIOは使えないのか

一言で言えば「PIO制御用ペリフェラルがPCIeから見えるメモリにmapされていないから」らしいです。

Pi5でPIOが使えるかはMichaelBellさんがすでに調査して共有してくれています。

rp1-hacking/PIO.md at main · MichaelBell/rp1-hacking · GitHub

こちらには以下のように書かれています。

The PIO registers are accessible at address 0xf000_0000 from the RP1. Additionally the FIFOs (only) are accessible at 0x40178000 and hence from Linux (at 0x1f_00178000). rp1-hacking/PIO.md at main · MichaelBell/rp1-hacking · GitHub より引用

つまり、LinuxからはPIOのFIFOしかアクセスできず、PIOの制御レジスタはRP1のプロセッサからしかアクセスできないメモリにいるようです。 本当にそうなっているのでしょうか?

メモリマップの調査

PCIeデバイスの制御は、デバイスの持つメモリをホストのメモリにマップし、そこにアクセスして行います(参考: https://osdev.jp/wiki/PCI-Memo)。

RP1はPCIe経由で接続されているので、RP1のメモリもホストのメモリの何処かにマップされています。

どこにマップされているかは、以下の起動時のログやドライバを眺めたり、mmapして実際にメモリを読んでみると、 RP1の 0x4000_0000 がホストの 0x1F_0000_0000 にマウントされているとわかります。

[    1.767860] pci 0000:01:00.0: BAR 1: assigned [mem 0x1f00000000-0x1f003fffff]
[    1.775026] pci 0000:01:00.0: BAR 2: assigned [mem 0x1f00400000-0x1f0040ffff]
[    1.782192] pci 0000:01:00.0: BAR 0: assigned [mem 0x1f00410000-0x1f00413fff]
...
[    1.836165] rp1 0000:01:00.0: bar0 len 0x4000, start 0x1f00410000, end 0x1f00413fff, flags, 0x40200
[    1.845252] rp1 0000:01:00.0: bar1 len 0x400000, start 0x1f00000000, end 0x1f003fffff, flags, 0x40200
[    1.854518] rp1 0000:01:00.0: enabling device (0000 -> 0002)
[    1.861119] rp1 0000:01:00.0: chip_id 0x20001927

具体的には以下のように調べていきました。

Linuxから見えるPIOレジスタ?のチェック

RP1のマニュアルによるとPIOはRP1のメモリの0x40178000にマップされているらしいです。 そこでLinuxから 0x1f_0017_8000 にアクセスしたところ、こんな値が読めました。

(余談: このメモリは32bitずつしか読み込めないです。8bitずつ読み込むと上位24bitが0xffになります。なぜ...?)

# 左が 0x40178000 からのoffset、右が読み込んだ32bit値

map ok
read pio registers
0x000000 : 00000000
0x000004 : 00000000
0x000008 : 00000000
0x00000c : 00000000
0x000010 : 418c2041
0x000014 : 2d8ef0c6
0x000018 : 42c753b3
0x00001c : d61f584b
0x000020 : 70696f33
0x000024 : 00000000
0x000028 : 00000001
0x00002c : 00000000
0x000030 : 00000000
0x000034 : 00000000
0x000038 : 00000001

MichaelBellさんの調査結果より、RP1のPIOのFSTATレジスタはオフセット0x04にいるはずです。 このレジスタには何らかの値が入っているはずなので、0が読み出されるのはなにか変です。 よって、少なくともこのアドレスにPIOの制御レジスタがないことは確かそうです。

0xF000_0000 にあると言われているPIOレジスタLinuxから読めないのか

RP1のマニュアルの「Table 1. Address Map summary」と「Table 2. Peripheral Address Map」を見る限り 0xF000_0000 は外部に見えるアドレスが割り当てられてなさそうなので、厳しそうです。

画像は https://datasheets.raspberrypi.com/rp1/rp1-peripherals.pdf のTable 1. Address Map summary,pp.7 より引用

以上より、今のところPIOはLinuxから簡単に扱えなさそうという結論になりました。

MichaelBellさんはどうやってPIOを使おうとしているか

フォーラムでの投稿やgithubのコードを見る限りでは、G33katWorkさんのRP1リバースエンジニアリングの成果を元にRP1でPIOを制御するコードを動かそうとされているようです。

GitHub - G33KatWork/RP1-Reverse-Engineering: Experiments on the RP1

rp1-hacking/launch_core1 at main · MichaelBell/rp1-hacking · GitHub

まだコードをきちんと理解できていないのですが、どうもShared SRAMに自作のコードを置いたあと、WatchDogを制御してリセットをかけてRP1のCore1で自作コードを動かしているみたいです。

このやり方についてRaspberry Pi エンジニアのjdbさんは以下のように言われています。

You are free to hack around with the hardware, but for anyone else wanting to experiment with this, heed these warnings: The RP1 firmware expects unfettered access to the entirety of shared SRAM, starting at 0x2000_0000. Arbitrary modification of any part of the memory region may cause side-effects up to and including loss of data and hardware damage. Using RP1 and PIO on Raspberry Pi 5 - Raspberry Pi Forums より引用

意訳すると「やるのは自由だけど、壊れるかもしれないから気をつけてね」という感じでしょうか。

その後の投稿で「core1もそのうち使えるようにする」と言われているので、それを気長に待つと良いのかなと思います。 (こういうHackやるようにメモリ1Gだけどお手頃価格なPi5出たら嬉しいなー)

おしまい

以上です。

参考文献