macOSからPi Picoを使う - その12 [Pi Pico]
Pi PicoのC-sdkを使ってGPIO、PWM、ADCなんかをマルチコアで動かすやり方がなんとなくわかってきた。直近ではやりたいことはmacOSをホストにしてPi Picoを経由したハードウェア制御をやりたい。そのための準備...
最終的にはプロトコルを統一して、矛盾なく識別できるようにしたいけど、まだそこまで考えられない。とりあえずハードウェアを区別する手段を用意して、それに従ってソフトウェアと接続できるかどうかを判断することにする。
Pi PicoをCDCデバイスとしてmacOSにUSBで繋いだとき、デバイスファイルの名前がどうなるのかわからないので、それを基準に判断はできない。まずデバイスをファイルをオープンして、何らかの文字列をCDCに投げると、個体識別のためのIDを返すようにしよう。
Pi Pico基板はhardware_flashモジュールの
という関数で合計8バイトのデータで識別できるらしい。これはPi Pico基板に乗っているflashメモリのRUIDというデータそのもので、これはflashデバイスに固有に割り当てられているらしい。flashメモリは基板に直付けされているので、Pi Picoに固有のデータだとみなしていい、ということである。
これで基板を区別して、あとは書き込んだプログラムの名前とバージョンとを組み合わせて、問い合わせに答えることにしよう。そうするとこれからPi Picoに書くプログラムはまずそれに応答できるようにしないといけない。
本来はシリアルナンバが割与えられていて、USBのdescriptorを読み込めばそれがわかるようになっているのが一番いいけど、pico_stdioを使うとdescriptorの中身はpico-sdk/src/rp2_common/pico_stdio_usb/stdio_usb_descriptors.cにハードコードされてしまっていて、プログラムごとに書き換えないといけない。
今後のsdkのバージョンが変わると違ってしまうかもしれないのでそういうことはやめたほうがいい。そうするとTinyUSBを自力で書くか、USBで接続したあと、IDを読み出す上位プロトコルを決めてみなそれに合わせる、ということになる。
まあ、最初は上位プロトコルだな。そのあとはdescriptorを考えよう。Pi Picoのシリーズもこれから色々出そうだし、今使っているRaspberry PiがPi Picoに置き換えられそうなものもあるので、ちょっと真面目に考えないといけない。
従って、Raspberry PiとmacOSとの間で通信をしていて、そのプロトコルをあらかじめ(実はその場その場で適当に)決めている。通信のコードはRaspberry PiとmacOSで共通にしないといけない。Raspberry PiとmacOSではPISOXのレベルでは全く同じコードが動く(これまで固有のデバイス名などを除いて同じコードが動かなかったことはなかった)ので、どちら用にコンパイルするか、というのをコードに埋め込んだことはなかった。厳密に言えば、プラットフォーム依存のコードはそれぞれにあるし、整数型のサイズの違いなんかはあるけど、ユーザコードで振り分ける必要はなかった。
ところがPi Picoでは全く違う。なるべく同じコードにしようと思うんだけど、sdkの中以外は一切使えない。そこでコードを切り替える必要がある。
たとえばmacOSのclangではどこで定義されているのかわからないんだけど、
と定義されているので、それを使えばいい。x86とM1とを区別したいなら
かあるいは
これと同等なPi Picoのマクロはというとあまり見つからない。
tinyusbのソースを見るとRP2040を積んだボードを区別するのに
というマクロを使っている。これがボードごとに違っているらしいけど、どこで定義されているのかやっぱりわからない。とりあえずこれを使ってPi Picoを区別するか。
またRaspberry PiとPi Picoには
とあるので、これでmacOSと区別して本家には
とあるので、これでPicoと区別するか。でもこれだとPico以外のeabiも入ってしまうか。でも僕はそれ以外のを使わないのでいいか。
何か的確なスイッチはないものだろうか。
そしてもう一点、Raspberry Piは完全なunixでありながら、GPIOなんかの超低レベルのハードウェア制御が可能になっているということ。他のmacOSをはじめとするunixではハードウェアを直接触ることは非常に難しい。特にmacOSでは実質的に不可能、と言っていい。Raspberry Piではその敷居はすごく低くなっている。実際に手で触って自分でハンダ付けしてプログラムしてデータを得ることができる。手を近づけるだけでノイズが増える、とかいう身体感覚は初々しくて結構楽しい。
そういう両極端を併せ持ってるハードウェアは案外なかった。これはよく考えれば不思議なことに思える。僕がunixをいじり始めた1980年台にはエンジニアリングワークステーションと言ってunix(当時はSystemVかBSDの2択だった)にX-Windowを積んだMC680x0ベースのコンピュータがあった。僕がよく使ったのはHPのもので、拡張バスにVMEを使っていた。拡張バスといってもCPUのバスがそのまま引き出されたもので、しかもバス調停は単純でEurocardの大型基板にTTLを手ハンダすることができた。NTSCカメラ用のフレームグラバなんかは生産技術の連中が起こした9801用のグラバ回路をVMEに乗せてもらったりした(「VMEは基板が広くていいなあ」とか言われた)。
そうやってハードウェアを作ってソフトを書いて自前の測定機を何種類も作った(一番たくさん作ったのは赤外半導体レーザ光原の干渉計で、当時汎用の干渉計はHe-Neレーザを光源にしているものしかなかったが、光ディスクに使う対物レンズはN.A.が高くて、単に波長換算するだけではうまくいかない場面があった。今でも干渉計だけは何もないところから部品を集めてソフトを書いて僕ひとりで1台でっち上げることができる)。
つい昔話を始めると長くなってしまうけど、Pi Picoはその低レベルハードウェア制御の面だけを取り出したものだった。この分野では実はPi Picoは最後発と言って良くて、昔からあってもっとも大手で裾野も広いのがArduinoだった。
Pi Picoは後発の分、それと本家での積み重ねのおかげでArduinoに比べて高性能でメモリも多く、そのくせ安い、というおいしい状況ができた。残るArduinoとの違いはユーザの数とそれによる実働実績やライブラリの充実である。
ハードウェア制御の性能としては本家Raspberry Piより高いと言っていい。ハードウェアPWM信号、I2C、SPIなどは本家では使えるGPIOピンが限られているけどPi Picoではどれもほとんどのピンで使えるようになっている。PWMの周波数もPi Picoの方が広いレンジに設定できる。
さらにPIOという特殊なステートマシンを持っていて、これは僕みたいな高レベルのプログラミングばかりしてるとピンとこないけど、ハードウェアに近いプログラミングに慣れた人なら色々面白いことが考えられるだろう。使いこなすことができればかなりいろいろなことができるはずである(僕もひと段落したらPIOに挑戦したいと思っている)。
本家Raspberry Piではそういうハードウェア操作のAPIは実際にはあまり整備されなかった。wiringPiやpigpioといたユーザの作ったライブラリが使われてきた。
Pi PicoではFoundationが思い直したのか、別の野心があるのか、ちゃんとしたsdkとマニュアルが整備された。もともとベアメタルではレベルの差こそあれ、コンパイラを含めて周辺のライブラリなどを整備しないと誰も使わないけど、Foundationとしてはlinux環境におんぶに抱っこだったので、画期的なことである。
FoundationとしてこれからPi Picoをどう持っていきたいのか、というのは重要である。Arduinoを駆逐するのが目的ならそれは難しくなさそうである。しかしそれはユーザから見ればまったく意味がないし、本来の教育目的という趣旨とは相入れない。
本家のRaspberry Piは互換性を維持しつつ性能を上げて、Pi Picoは互換性よりもハードウェア制御のバリエーションを増やす、と言う方向がユーザには望ましいだろう。どうするのか期待したい。
11 個体識別
Pi PicoのUSB descriptorにはVendorIDとProductIDが入っているが、SerialNumberはどれも0になっている。従って複数個繋いだ場合や、機能の異なるハードウェアを持ったものをUSBに繋いだ場合など、を識別できないといけない。最終的にはプロトコルを統一して、矛盾なく識別できるようにしたいけど、まだそこまで考えられない。とりあえずハードウェアを区別する手段を用意して、それに従ってソフトウェアと接続できるかどうかを判断することにする。
Pi PicoをCDCデバイスとしてmacOSにUSBで繋いだとき、デバイスファイルの名前がどうなるのかわからないので、それを基準に判断はできない。まずデバイスをファイルをオープンして、何らかの文字列をCDCに投げると、個体識別のためのIDを返すようにしよう。
Pi Pico基板はhardware_flashモジュールの
void flash_get_unique_id(uint8_t *id_out);
これで基板を区別して、あとは書き込んだプログラムの名前とバージョンとを組み合わせて、問い合わせに答えることにしよう。そうするとこれからPi Picoに書くプログラムはまずそれに応答できるようにしないといけない。
本来はシリアルナンバが割与えられていて、USBのdescriptorを読み込めばそれがわかるようになっているのが一番いいけど、pico_stdioを使うとdescriptorの中身はpico-sdk/src/rp2_common/pico_stdio_usb/stdio_usb_descriptors.cにハードコードされてしまっていて、プログラムごとに書き換えないといけない。
今後のsdkのバージョンが変わると違ってしまうかもしれないのでそういうことはやめたほうがいい。そうするとTinyUSBを自力で書くか、USBで接続したあと、IDを読み出す上位プロトコルを決めてみなそれに合わせる、ということになる。
まあ、最初は上位プロトコルだな。そのあとはdescriptorを考えよう。Pi Picoのシリーズもこれから色々出そうだし、今使っているRaspberry PiがPi Picoに置き換えられそうなものもあるので、ちょっと真面目に考えないといけない。
12 コンパイラフラグ
僕はたぶんPi Picoを単独で使うことは少なくて、macOSのUSBポートに挿して低レベルのハードウェア制御のためのインターフェイスとして使うことになると思う。今でも本家Raspbery Piを10台以上使ってるけど、単独で動いているのは気温や湿度などの環境データを取ってはファイルサーバに落とす、というのだけで、それ以外はなんらかの形でmacOSのサーバとして動いている。従って、Raspberry PiとmacOSとの間で通信をしていて、そのプロトコルをあらかじめ(実はその場その場で適当に)決めている。通信のコードはRaspberry PiとmacOSで共通にしないといけない。Raspberry PiとmacOSではPISOXのレベルでは全く同じコードが動く(これまで固有のデバイス名などを除いて同じコードが動かなかったことはなかった)ので、どちら用にコンパイルするか、というのをコードに埋め込んだことはなかった。厳密に言えば、プラットフォーム依存のコードはそれぞれにあるし、整数型のサイズの違いなんかはあるけど、ユーザコードで振り分ける必要はなかった。
ところがPi Picoでは全く違う。なるべく同じコードにしようと思うんだけど、sdkの中以外は一切使えない。そこでコードを切り替える必要がある。
たとえばmacOSのclangではどこで定義されているのかわからないんだけど、
#define __APPLE__ 1
#define __x86_64 1 #define __arm64 1
#define __arm64__ 1 #define __x86_64__ 1で区別すればいいだろう。そのためのマクロだと思われる。
これと同等なPi Picoのマクロはというとあまり見つからない。
tinyusbのソースを見るとRP2040を積んだボードを区別するのに
PICO_BOARD
またRaspberry PiとPi Picoには
#define __ARM_EABI__ 1
#define __unix 1
何か的確なスイッチはないものだろうか。
13 ここまででわかったこと
僕がこれまでなんでRaspberry Piをいっぱい使ってきたかというと、まず1番にはunixとして完全だ、ということ。僕はunixを40年近く使ってきた。コンピュータの世界ではドッグイヤーとか言われて、特にウェブの世界では半年で使うフレームワークがころっと変わってしまったりするけど、unix、というかPISOX標準という規格のおかげで40年前の僕のunixに関する知識が今でも有効である。これは新しいことを学ぶ必要が起きてもすっぴんの状態から始めなくてもいい、ということがよくあって効率がいい。そしてもう一点、Raspberry Piは完全なunixでありながら、GPIOなんかの超低レベルのハードウェア制御が可能になっているということ。他のmacOSをはじめとするunixではハードウェアを直接触ることは非常に難しい。特にmacOSでは実質的に不可能、と言っていい。Raspberry Piではその敷居はすごく低くなっている。実際に手で触って自分でハンダ付けしてプログラムしてデータを得ることができる。手を近づけるだけでノイズが増える、とかいう身体感覚は初々しくて結構楽しい。
そういう両極端を併せ持ってるハードウェアは案外なかった。これはよく考えれば不思議なことに思える。僕がunixをいじり始めた1980年台にはエンジニアリングワークステーションと言ってunix(当時はSystemVかBSDの2択だった)にX-Windowを積んだMC680x0ベースのコンピュータがあった。僕がよく使ったのはHPのもので、拡張バスにVMEを使っていた。拡張バスといってもCPUのバスがそのまま引き出されたもので、しかもバス調停は単純でEurocardの大型基板にTTLを手ハンダすることができた。NTSCカメラ用のフレームグラバなんかは生産技術の連中が起こした9801用のグラバ回路をVMEに乗せてもらったりした(「VMEは基板が広くていいなあ」とか言われた)。
そうやってハードウェアを作ってソフトを書いて自前の測定機を何種類も作った(一番たくさん作ったのは赤外半導体レーザ光原の干渉計で、当時汎用の干渉計はHe-Neレーザを光源にしているものしかなかったが、光ディスクに使う対物レンズはN.A.が高くて、単に波長換算するだけではうまくいかない場面があった。今でも干渉計だけは何もないところから部品を集めてソフトを書いて僕ひとりで1台でっち上げることができる)。
つい昔話を始めると長くなってしまうけど、Pi Picoはその低レベルハードウェア制御の面だけを取り出したものだった。この分野では実はPi Picoは最後発と言って良くて、昔からあってもっとも大手で裾野も広いのがArduinoだった。
Pi Picoは後発の分、それと本家での積み重ねのおかげでArduinoに比べて高性能でメモリも多く、そのくせ安い、というおいしい状況ができた。残るArduinoとの違いはユーザの数とそれによる実働実績やライブラリの充実である。
ハードウェア制御の性能としては本家Raspberry Piより高いと言っていい。ハードウェアPWM信号、I2C、SPIなどは本家では使えるGPIOピンが限られているけどPi Picoではどれもほとんどのピンで使えるようになっている。PWMの周波数もPi Picoの方が広いレンジに設定できる。
さらにPIOという特殊なステートマシンを持っていて、これは僕みたいな高レベルのプログラミングばかりしてるとピンとこないけど、ハードウェアに近いプログラミングに慣れた人なら色々面白いことが考えられるだろう。使いこなすことができればかなりいろいろなことができるはずである(僕もひと段落したらPIOに挑戦したいと思っている)。
本家Raspberry Piではそういうハードウェア操作のAPIは実際にはあまり整備されなかった。wiringPiやpigpioといたユーザの作ったライブラリが使われてきた。
Pi PicoではFoundationが思い直したのか、別の野心があるのか、ちゃんとしたsdkとマニュアルが整備された。もともとベアメタルではレベルの差こそあれ、コンパイラを含めて周辺のライブラリなどを整備しないと誰も使わないけど、Foundationとしてはlinux環境におんぶに抱っこだったので、画期的なことである。
FoundationとしてこれからPi Picoをどう持っていきたいのか、というのは重要である。Arduinoを駆逐するのが目的ならそれは難しくなさそうである。しかしそれはユーザから見ればまったく意味がないし、本来の教育目的という趣旨とは相入れない。
本家のRaspberry Piは互換性を維持しつつ性能を上げて、Pi Picoは互換性よりもハードウェア制御のバリエーションを増やす、と言う方向がユーザには望ましいだろう。どうするのか期待したい。
2021-06-27 22:33
nice!(0)
コメント(0)
コメント 0