ラズパイPicoにTinyGoのオブジェクトを書き込んでラズパイPicoハードウエアをどう制御したものか手探りしてます。今回はTIMERにやってまいりました。TinyGoのmachineパッケージから直接TIMER使えないのだけれど、調べてみるとTIMERはしっかり使われている形跡があります。使っているのは誰ぞ?
※「GoにいればGoに従え」Go関連記事の総Index
※実機動作確認は Arm Cortex-M0+コアのRP2040チップ搭載、Raspberry Pi Pico機にTinyGoのオブジェクトを書き込んで行っています。ビルドはWindows11上です。
※RP2040のデータシート(PDF)はこちら
Raspberry Pi Picoのタイマ
ラズパイPicoのペリフェラルは、「普通の」半導体屋さんのマイコン搭載のペリフェラルに比べると「一味違う」味付けです。タイマもユニーク。勝手にかいつまむとこんな感じ。
-
- 普通のマイコンのタイマであると、タイマの周期などを設定するために、クロック選択、プリスケーラの設定、リロード値の設定など一杯設定がある。ラズパイPicoのタイマは、1μ秒単位で固定。メンドクサイ設定などなし。
- 普通のマイコンのタイマであると、カウント幅は用途に応じて8ビット、16ビットなどあり、せいぜい32ビット最大。アップ、ダウンカウントもあり。またタイマ本数は多数。しかし、ラズパイPicoのタイマは64ビット幅のアップカウント1本。
- 普通のマイコンタイマには、PWM出力、インプットキャプチャなど入出力機能が付随している(というかそれがメインのお仕事であることが多い。)ラズパイPicoの場合、それら入出力機能はPWMモジュールに追い出されており、TIMERは純粋に時間を測る機能のみ。
- ラズパイPicoの場合、64ビットのカウント値に対して下32ビットのアラーム値を比較してアラーム割り込みを発生させる。アラームは4本。
このような特徴のラズパイPicoのタイマ、TinyGoで記述した「ユーザ」プログラムから使えるのだか、使えないのだか、ちょっとばかり探ってみました。
実験に使用したTinyGoソース
いつもながら、手抜きでベタなTinyGoのソースです。何もTIMERに設定していないのだけれど、タイマのカウンタが動いているのか、また、アラームが使われているのか探るもの。ただし、アラームは0番と3番だけ調べてます。1,2が無いのはメンドかっただけっす。
package main import ( "device/rp" "fmt" "runtime/volatile" "time" ) func main() { tim := rp.TIMER for { RAWL := volatile.LoadUint32(&tim.TIMERAWL.Reg) fmt.Printf("RAWL: %d\n", RAWL) ARMEDf := tim.GetARMED() fmt.Printf("ARMED: 0x%01x\n", ARMEDf) R0 := tim.GetINTR_ALARM_0() E0 := tim.GetINTE_ALARM_0() F0 := tim.GetINTF_ALARM_0() S0 := tim.GetINTS_ALARM_0() fmt.Printf("0) R:%d E:%d F:%d S:%d\n", R0, E0, F0, S0) A0 := volatile.LoadUint32(&tim.ALARM0.Reg) fmt.Printf("ALARM0: 0x%08x\n", A0) R3 := tim.GetINTR_ALARM_3() E3 := tim.GetINTE_ALARM_3() F3 := tim.GetINTF_ALARM_3() S3 := tim.GetINTS_ALARM_3() fmt.Printf("3) R:%d E:%d F:%d S:%d\n", R3, E3, F3, S3) A3 := volatile.LoadUint32(&tim.ALARM3.Reg) fmt.Printf("ALARM3: 0x%08x\n", A3) time.Sleep(time.Second * 4) } }
実機動作確認
上記のソースをビルドして走らせ、USBシリアルに出力されてくる出力をキャプチャしたものが以下に。
まずは、予想通りな事柄。RAWLの出力は毎回異なった値が読めています。よって、
-
- タイマのカウンタは特に初期設定しなくても走っている
続いてアラームについて分かったこと。
-
- アラーム0の割り込みはイネーブルになっている上、アラーム0の設定値は毎回更新されているように見える
- 一方、アラーム3の割り込みはディセーブル。アラーム3の設定値はゼロのまま動かない。
いったい「誰が」アラーム0を使っているのか?試みにALARM0の設定値のインターバルを計算してみました。こんな感じ。
0x0356a75b – 0x3199bcb = 0x3D0B90
上記の結果を十進にすると4000656、つまりは約4秒! 胸に手を当ててよーく考えたら心あたりがありました。これだ、これに違いない。。。
time.Sleep(time.Second * 4)
time.Sleep()関数に与えた引数の値みたいね。そうか、time.Sleep()がALARM0を使っているようだね。。。そうだったら尊重しないと。てゆうか、time.Sleep()あればよくね。