Timerの精度(RPiベアメタルMicroPython)

昨日のTimerクラスの割り込み処理を使ったLチカはこんな感じになります。
Raspberry Pi Zero Wなので、GPIO47がボード上のLEDです。

このタイマ割り込みの精度はどの程度になるのか、測定してみました。
1000マイクロ秒(1msec)周期の割り込みをかけて、コールバック関数の中でそのときの時刻を測定します。
割り込み処理が実行される時刻が、割り込みが起こった時刻からどれくらい遅れるか統計を取ってみます。

Timer.compare_register()は、「次に割り込みが起きるタイミング」を示しています。System Timerでは、フリーランニングする1MHzクロックのカウンタ(utime.ticks_usec()を実現している64bitカウンタ)の下位32bitが、タイマのコンペアレジスタと一致したときに割り込みが起こります。

割り込みが起きるタイミング自体は、utime.ticks_usec()の計測値で見ればきっかり1000マイクロ秒間隔になります。
しかし、コールバック関数は割り込みハンドラ内ではなく、ハンドラの処理が終わった後に呼ばれますので、割り込みから割り込みハンドラの実行までにはオーバーヘッドがあり、その分遅延が出ます。

この遅延の量を、logへ蓄積していきます。
遅延の値は、「現在時刻 – (コンペアレジスタの値 – 1000)」になります。
「-1000」が付いているのは、Pythonで書いた割り込みハンドラが呼ばれたタイミングでは、既に割り込みが起きてコンペアレジスタの値が更新され、次回割り込みが起こるべきタイミングを示す値になっているからです。

試しに1000回測定してみた結果は以下のようになりました。

timer-accuracy.png
47	317
48	260
49	187
50	143
51	56
52	38

割り込みそのものからの遅延は50マイクロ秒前後です。
割り込みの間隔そのものは概ね5マイクロ秒以内の変動で納まっています。
今回は割り込みタスク以外にはwhileループしか走っていませんが、もっと重い処理(実行時間が長くかかるCの関数の実行)をさせればもちろん悪化する可能性はあります。
上の例はUSBキーボードのサポートをオフにして測定したものですが、USBキーボードを接続した状態だと以下のように少し変動が増えます。

timer-accuracy-with-usb.png
48	248
49	217
50	160
51	108
52	91
53	37
54	37
55	37
56	36
57	30

遅延の最大値が5マイクロ秒ほど増えています。
現在の実装では、割り込みハンドラの実行は特に優先されないので、定期実行するタスクが増えるほど、変動が増えていくと思われます。

コメント