液晶の表示を高速化


ili9325のパラレルインターフェース液晶の表示を高速化してみました。

当初mruby-bsdgpioで1ビット単位でアクセスしていたのですが、これでは効率が悪すぎます。

pcduinoで使われているallwinner A10のデーターシートを見たところgpioはport単位でのアクセスになるようです。

またarm/allwinner/aw_gpio.cを見てみたところ32ビット単位でのアクセスがサポートされていました。

基板で作り直したときにデーターバスを同じポートにまとめて一回でアクセスできるようにしてみました。

新しいmrbgemsを作るのも面倒なので、mruby-bsdgpioを継承したクラスにメソッドを追加する事にしました。

特に必要ないのでinitializeは用意してません。DATA_PTRも親のデータをそのまま使います。高速化のためにwriteregとsetlineというメソッドを用意しました。

GPIOのポートはPHとPIなので、これをまとめて処理しています。

信号線を整理したときにWRはデータバスと同じポートにしていました。たまたまなんですが、このおかげで一回のioctlでストローブできます。書き込みの方が多いので、良いと思います。

x(0x0020),y(0x0021)はpixelを送るとインクリメントされるようなので、一度だけ送るようにしました。またpixelのレジスタアドレス(0x0022)を1度送った後は、連続してpixelデータを送るようにしました。

これで当初表示に70秒くらいかかっていたのが1秒まで短縮できました。

def lcdCopy(g, c)
  arr = Array.new
  for i in 1..320 do
    rgba = c.getpix(0, i - 1, 240)
    g.setline(0,320 - i, 240, rgba)
  end
end

g = GpioTft.new(0)
lcdInit(g)
lcdReset(g)
lcdSetWriteDir(g)
lcdSetup(g)

c = Cairo.new(240, 320)
c.set_source_rgb(1 , 0, 0)
c.move_to(0, 0)
c.line_to(100, 100)
c.stroke()

lcdCopy(g, c)

この液晶はデフォルトでは左下が0,0で初期化のパラメータで変更できるようなのですが、分からなかったので、コピーするときに左上が0,0になるようにしてます。

ちなみにこの32ビットアクセスのioctlのGPIOACCESS32はおもいっきりバグっていました。

第四引数が間違えてます。誰も使ってないのかもしれませんね。^ ^;

32ビット単位でのまとめての処理はaccessとconfigがあって、後から追加されたようです。まだlibgpioではラップされてません。

A10は中華パッドによく使われたSOCです。これらは内蔵のLCDコントローラーを使っているので高速な描画が可能ですが、GPIOにつながったLCDコントローラーではこんなところが限界かもしれません。

追記

cairoで変更のあったところだけをコピーするように、mruby-cairoにstroke_extentsというメソッドを用意してみました。strokeメソッドを呼ばれた以降にlineなどの変更領域が拾えます。

def lcdCopyExtents(g, c, rect)
  arr = Array.new
  x1 = rect[0].floor
  y1 = rect[1].floor
  x2 = rect[2].ceil
  y2 = rect[3].ceil
  for i in y1..y2 do
    rgba = c.getpix(x1, i - 1, x2 - x1)
    g.setline(x1, i, x2 - x1, rgba)
  end
end

c.move_to(100,0)
c.line_to(100, 100)
rect = c.stroke_extents()
c.stroke()
lcdCopyExtents(g, c, rect)

sleep 2

c.move_to(0, 100)
c.line_to(100, 100)
rect = c.stroke_extents()
c.stroke()
lcdCopyExtents(g, c, rect)

SPIインターフェースのLCDの高速化のためにフレームデータのmrubyでの処理をなくしてみたのですが、同じようにポインター渡しにしてみました。しかし見えるほどの効果はなかったです。A10はpowerがあるのでmrubyでのオーバーヘッドが小さいのかもしれません。

初期化ルーチンをmruby-gpiotftのmrbgemのrubyコードに移してローカルの変数を追加するためにCコードにinitializeを入れました。

mruby-gpiotftのrubyコードとCコードにポートがハードコードされています。ポートのどこに接続されているかで32ビットアクセスが変わってくるので汎用化する良い方法が思いつきません。

mrbgemのrubyコードが動かなくてちょっとはまったのですが、rubyコードにも依存関係を書いておく必要がありました。