mruby/cでタイムスタンプを取得


mruby/cを用いて、ある信号のモニタをしようと思ったのだが、それには時間に対して信号がどうなっているのかを記録する必要があった。 しかし、mruby/cでは、sleepなどはできるが、現在の時間を取得することはできない。 arduinoだと、micros()で起動してからの時間がマイクロ秒単位で取得できるのだが、これに相当する機能をmruby/cに実装することにした。

まず、methodの名前をどうするかを悩んだが、ticks_usとすることにした。 mruby/cの整数はdefaultでは32bitなので、一時間と少しで零に戻ることになるが、通常は問題無いだろう。 整数を64bitにもできるが、メモリを食うので、 32bitのままで使うことにした。 ch32funでこれを実現するには、micros()に対応する関数は無いが、クロックを数える関数があるので、何クロックがマイクロ秒に対応するかを考えれば良い。 mruby/c用に、ch32funでマイクロ秒単位のタイムスタンプを返す関数を以下のように定義した。

static void c_ticks_us(mrbc_vm *vm, mrbc_value v[], int argc){
  SET_INT_RETURN( funSysTick64()/DELAY_US_TIME );
}

あとは、これをmethodとして定義すれば、rubyから使えるようになる。

mrbc_define_method(0, 0, "ticks_us", c_ticks_us);

しかし、この機能を組込んでコンパイルしたら、1k以上も大きくなってしまった。 今回は時間が必須なので仕方無いが、通常はこの機能は組込まないで良いだろう。

ch32x035を使って、

while true
  printf "%d\r\n",ticks_us
  sleep_ms 1
  printf "%d\r\n",ticks_us
  sleep 1
end

を実行したら、2.1msぐらいの時間が消費されていた。 10msだけsleepするようにしたら11.1msぐらいかかったので、 sleepの前後の処理と表示する部分で1msぐらいかかっているようだ。

二つの信号の変化があったときに、その時間とピンの状態を表示するために、 以下のようなプログラムを走らせてみた。

green=GPIO.new(25,GPIO::IN)
blue=GPIO.new(35,GPIO::IN)
pg=0
pb=0
while true
  g=green.read
  b=blue.read
  next if pg==g and pb==b
  printf("%d,%d,%d\r\n",ticks_us,pg=g,pb=b)
end

これを使って信号をモニタしたところ、 ある信号は約500マイクロ秒で変化したように表示されるので、表示自体はそれ以下の時間で行われているようだ。 表示時間を考慮するならば、信号を一旦は配列にためておいて、まとめて表示すると良いかも知れない。