今回はRaspberry Pi Pico君の秘められしポテンシャルを拝ませてもらうべく、
PIO(Programable IO)に触れていきたいと思います。
PIO(Programable IO)とは
これ↓見てください
https://interface.cqpub.co.jp/wp-content/uploads/if2108_176.pdf
つまりはCPUのリソースを消費しない、超小規模マイコンが計8つ載ってるようなイメージになります
なにをやるか
こちら↓に公式がMicroPythonで書いた例がいくつかあります。
github.com
LチカからWS2812(通称:流れるテープLED)の制御、
uartやspiまで、様々な処理をCPUに頼らずに行えます。
なんて魅力的なんでしょうか…
さあ、そんなPIOを使いたいな~と思っていた矢先に、友人より
「ns(ナノ秒)単位で時間計測したいんだが」
という相談を受けました。
ナノ秒というと相当早いので並大抵のマイコンでは計測は不可能ですし、PythonをPC上で動かして実験してみても厳しかったです。
こういうのは基本的にFPGAやらなんやらを使うのが定番って感じでした。
いやしかし、PIOならできるのでは??
ということで、今回はPIOでナノ秒単位時間計測をしていこうと思います!
開発環境
Raspberry Pi Picoはいくつかの言語・環境に対応しているわけですが
今回は私のPython嫌いを治すべく、MicroPythonを使って開発を行いました。
使ったIDEはこちら↓の「Thonny」を使用しました。
thonny.org
なんかこう、なんとなくおぞましいアイコンをしていますね...
.pyファイルを開く標準ソフトに設定すると、たくさんアイコンが並んでしましい、なんだか恐怖を感じます。
しかしながら、ソフト自体はシンプルかつ簡単で、即座にRaspberry Pi Picoの開発に着手できました。
プログラム
import rp2 from machine import Pin PIO_IN_PIN0 = Pin(6, Pin.IN, Pin.PULL_UP)#GP6を入力・プルアップに設定 @rp2.asm_pio(in_shiftdir=rp2.PIO.SHIFT_LEFT) def count(): pull()#TX FIFOのデータをosrに移動 mov(x,osr)#x=osr wait(0, pin,0)#ピンがLOWになるまで待機 label("loop") in_(pins,1)#ピンの状態1bit分だけisrに移動 mov(y,isr)#y=isr jmp(y_dec,"end")#y=0 で通過 それ以外はy=y-1してラベル:endにジャンプ jmp(x_dec,"loop")#x=0 で通過 それ以外はx=x-1してラベル:loopにジャンプ mov(x,osr)#x=osr label("end") mov(isr,x)#isr=x push()#isrのデータをRX FIFOに移動 sm = rp2.StateMachine(0, count, freq =-1 , in_base=PIO_IN_PIN0)#CPUの周波数と同スピードで設定 sm.active(1)#動作開始 machine.freq(200000000)#CPU周波数を200MHzに変更 print("begin") while True: sm.put(20000000)#TX FIFOに2千万を設定 print(20000000-sm.get(),end="count\n")#RX FIFOにデータが入るまで待機して、入ったら取り出してカウント数を計算、出力 #繰り返し
このプログラムを走らせた状態で、適当にGP6とGNDをショートさせると、以下のように大量のデータが吐き出されます。
これは接触時のチャタリングが原因ですかね
begin 0count 0count 0count 0count 12364939count 203count 4533count 60count 11929count 98count 514count 39count 27count 109count 243count 311count 13274count 5179count 667count 57count 10538828count 64count 35count 39count 24count 26count
※ちなみに0countは計測可能時間以上ショートさせた場合
今回周波数が200Mhz、PIOの処理1サイクルあたりにかかる時間は
1/200Mhz
なので5nsとなります。
PIOの命令はすべて1サイクルなので
開始処理にサイクル、1カウントあたり4サイクル、終了処理で3サイクル使い、(自信ないので適当)
(1+4×(カウント数-1)+3)×5ns
= 4×カウント数×5ns
に多分なると思います。
それで、デッドタイム(クールタイム?)は100nsくらいになるんじゃないですかね?(すっとぼけ)
そのため、最短計測可能は20ns、今回2千万を初期値に設定しているので最大計測時間は2千万×20nsで400msとなるはずです。
本当に測れてるか確認
実際に以下のプログラムを走らせたPicoに接続してみたところ、
from machine import Pin import time led=machine.Pin(22,machine.Pin.OUT) led1=machine.Pin(25,machine.Pin.OUT) while True: led.value(0) led1.value(1) time.sleep(0.1) led.value(1) led1.value(0) time.sleep(1)
以下のような出力が得られました。
begin 5001488count 5001640count 5001640count 5001539count 5001629count 5001529count
大体500万カウント、つまり
500万×20nsで1億ns=0.1秒
となりますので、ピンをON,OFFする時間を考慮すれば正しく計測できていることがわかります。
終わりに
ちなみにPIOで切り替え時間を20nsまで短くしたPicoを接続したとき、
ぎりぎり読めないこともありましたが、1カウントと出力されていました。
まあ私はオシロなんて持ってないので本当なのかは確認できませんね。
ということで私はㄑそ忌々しい受験勉強に戻りたいと思います。
では皆さんも良きPIOライフをお送りください~
(私へオシロを送ってくださってもいいですよ)
参考
rp2 --- RP2040 に固有の機能 — MicroPython 1.18 ドキュメント
Raspberry Pi Picoの仕様書を読んでみる(3) – 楽しくやろう。
RP2040のPIOで2bitバスで入力を受け付ける - chakokuのブログ(rev4)
MicroPython的午睡(15) ラズパイPico、プログラマブルIOの威力 | デバイスビジネス開拓団
そういえば最近「あなたのお子さんは私のことが好きですか?」
って勉強(??)が訴えかけてくる塾かなんかCMがありますが、イライラするのでやめてほしいです。
勉強好きなやつなんていねーよ!
ばーーーーーか!
失礼しました。