続・MicroPythonにTimerクラスを追加する(RPiベアメタル)

timer-free.png

先日作成したTimerクラスですが、複数タイマーのサポートやメソッドの追加を行いました。

今回追加した機能を含めたTimerクラスの仕様はこんな感じです。

・machine.Timer(id) {System Timerのインスタンスを作成する。idは1 or 3}

・init(period=a, mode=b, callback=c) {タイマを初期化し割り込みを開始する。最初の割り込みは呼び出し時点からperiodマイクロ秒後。modeはPERIODIC(繰り返し), ONE_SHOT(一度だけ), FREE(後述)のいずれか。callbackはselfを引数とする関数。パラメータ省略時のデフォルト値はperiod=4294967295、mode=PERIODIC、callback=None。}

・deinit() {割り込みを停止する。}

・counter(v) {vを与えなければ、init後に起きた割り込みの回数を返す。vを与えた場合は回数をvに設定する。}

・callback(f) {コールバック関数をfに設定する。コールバックさせたくないときはfをNoneにする。}

・period(n) {nを与えなければ、現在のタイマ周期の値を返す。nを与えた場合は周期をnマイクロ秒に設定する。}

インスタンスの作成時、idは0~3を指定できますが、実際に使用できるのは1と3で、0と2は使用できません。
以前も書いたように、System Timerの0番と2番はGPU側のシステム(VideoCore)で使われています。

0番と2番のタイマについても、割り込みを発生させること自体は可能です。
ただ、割り込みの周期を設定するコンペアレジスタはGPU側で設定されるので、CPU側から設定しても上書きされてしまいます。

実用的な意味はあまり無いですが、System Timer 0と2の挙動を観察できるように、タイマの動作モードとして「FREE」を用意しました。
このモードでは、コンペアレジスタの値はperiod()で読み出すことができますが、書き込むことはしません。
その代わり、IRQハンドラの中でコンペアレジスタの値をTimerオブジェクトのperiodに設定するようにしてみました。
つまり、例えばmachine.Timer(2).period()でSystem Timer 2のIRQ発生時点でのコンペアレジスタの値を観測できます。

以下の例は、System Timer 2の割り込みに応じてperiod()の値を観測します。

import machine
t2 = machine.Timer(2)
t2.init(mode=t2.FREE, callback=lambda t:print(t.period()))
t2.deinit()

動かしてみると、コンペアレジスタの値が勝手に更新されていくのが分かります。
間隔を調べても、100msecのときも1秒以上のときもあるという不規則さで、何に使われているのかは分かりませんが。
なお、コンペアレジスタの値はprint(obj)でも観測できます。(objはTimerのインスタンス)

コメント