cairoでLCDに表示

FTDIのFT245Rに[グラフィック有機ELモジュール](https://strawberry-linux.com/catalog/items?code=27342)(とりあえずLCD)をつないで、mruby-cairoでデータを作り表示してみました。いつものように環境はFreeBSD 12-Currentです。

LCDは4bitモードで利用して、データ4本のコントロール3本の接続にしています。

mrubyは[mruby-cairo](https://github.com/yamori813/mruby-cairo)と[mruby-ftdi](https://github.com/yamori813/mruby-ftdi)を入れてZRouterビルドしています。

```ruby
#
# LCD sample code on libftdi
#

class LCD4
  RW = 0x10
  RS = 0x20
  E = 0x40

  def lcd4init()
    @ftdi = Ftdi.new(0x6001, 0xff)
    @ftdi.baudrate(115200)
    @cache = 0
    self.out(0)
  end

  def out(ch)
    @ftdi.write([ch])
  end

  def cmd(ch)
    arr = Array.new
    c = (ch >> 4)
    arr << c
    arr << (c | E)
    arr << c
    c = (ch & 0xf)
    arr << c
    arr << (c | E)
    arr << c
    if @chache == 1 then
      @garr << arr
    else
      @ftdi.write(arr)
    end
  end

  def data(ch)
    arr = Array.new
    c = (ch >> 4) | RS
    arr << c
    arr << (c | E)
    arr << c
    c = (ch & 0xf) | RS
    arr << c
    arr << (c | E)
    arr << c
    if @chache == 1 then
      @garr << arr
    else
      @ftdi.write(arr)
    end
  end

  def start()
    @cache = 1
    @garr = Array.new
  end

  def flash()
    @ftdi.write(@garr)
  end
end

class HD44780 < LCD4
  Clear_Display = 0x10
  Return_Home = 0x02
  Set_Entry_Mode = 0x04
  Set_Display = 0x08
  Set_Cursor_and_Display_Shift = 0x10
  Set_Function = 0x20
  Set_CGRAM_Address = 0x40
  Set_DDRAM_Address = 0x80

  Decrement_Address = 0x00
  Increment_Address = 0x02
  Shift_Display_Off = 0x00
  Shift_Display_On = 0x01

  Display_Off = 0x00
  Display_On = 0x04
  Cursor_Off = 0x00
  Cursor_On = 0x02
  Blink_Off = 0x00
  Blink_On = 0x01

  Cursor = 0x00
  Display_and_Cursor = 0x08
  Left = 0x00
  Right = 0x04

  Data_Length_4 = 0x00
  Data_Length_8 = 0x10
  One_Display_Line = 0x00
  Two_Display_Lines = 0x08
  Font_5x7 = 0x00
  Font_5x10 = 0x04

  def initialize()
    lcd4init
    cmd(Set_Function)
    usleep(1000)
    cmd((Set_Function | Data_Length_4) >> 4 )
    usleep(100)
    cmd((Set_Function | Data_Length_4) | Two_Display_Lines)
    usleep(100)
    cmd(0x06)
    usleep(100)
    cmd(0x0f)
    usleep(100)
    cmd(0x1f)
    usleep(100)
    cmd(Return_Home)
  end

  def copylcd(c)
    for n in 1..2 do
      rgb16 = c.getpix(0, 8 * (n - 1), 100 * 8)
      start
      cmd(0x40 + (n - 1))
      for i in 1..100 do
        cmd(0x80 + (i - 1))
        pat = 0
        for k in 1..8 do
          if rgb16[1 + (i - 1) * 2 + 100 * (k - 1) * 2] == 0xff
            bit = 1
          else
            bit = 0
          end
          pat = pat | bit << (k - 1)
        end
      data(pat)
    end
    flash
    end
  end
end

t = HD44780.new

c = Cairo.new(100,16)

c.set_source_rgb(1, 1, 1)
c.set_line_width(1)
c.rectangle(0.5, 0.5, 99, 15)
c.stroke();

c.move_to(20, 12)
c.set_source_rgb(1, 1, 1)
c.font_create("/root/fonts/6x13.pcf")
c.set_font_size(13)
c.show_text("mruby cairo")
c.stroke();

t.copylcd(c)
```

![IMGP0080.JPG](https://qiita-image-store.s3.amazonaws.com/0/104066/b3564ee1-f2bc-7929-75c3-b698062e7117.jpeg)

白黒（単色）なので0xffかそれ以外で処理しています。

rectangleがx,yともに0.5になっているのはcairoではこのx,yを中心にしてwidthのラインを引くためです。0,0だと上と下のピクセルにまたがりデータを拾うと0xffになっていませんでした。

斜めの線はピクセルが0xffにならないので、このコードでは引けません。

漢字も表示できます。

![写真（2019-04-04 09.34）.jpg](https://qiita-image-store.s3.amazonaws.com/0/104066/42d88e18-f30b-84bf-70bc-1f519e3eed10.jpeg)

これはk8x12ですが、12ポイントくらいが収まりがよいです。

FreeBSDのツリーにパラレルポートを使ってLCDをコントロールするサンプルコードがありました。最近ではパラレルポートが付いたマシンはほとんどありませんが。

https://svnweb.freebsd.org/base/head/share/examples/ppi/