Onion Omegaに小型液晶をつないでみた


FreeBSDが動いているOnion OmegaAitendoで購入した小型液晶を接続してmrubyで表示を試してみました。

液晶のコントローラーはSitronixのST7735Bで128x160の表示ができます。

LinuxとラズパイとPythonで試されているこちらのページを参考にさせてもらいました。

接続は以下のように行っています。

SPI接続なのですが、ResetとRSというデータの種別を指定する信号が別に必要でこれらはGPIOで制御します。またSPIのデータ読み込みのためのMISOは接続されていません。

FreeBSDでユーザランドからSPIをコントロールするためのドライバspigenをmrubyから制御するためにmruby-bsdspiというgemを作ってみました。

以下をbuild_config.rbに追加してmrubyをビルドします。

   conf.gem :git => 'https://github.com/yamori813/mruby-bsdgpio.git'
   conf.gem :git => 'https://github.com/yamori813/mruby-bsdspi.git'  
#
# Original is this
# https://raspberrylife.wordpress.com/category/spi/
#

class ST7735
  RESET = 0
  RS = 8

  def initialize()
    @gpio = BsdGpio.new(0)
    @spi = BsdSpi.new(0)

    @gpio.setflags(RESET, BsdGpio::OUTPUT)  # reset
    @gpio.setflags(RS, BsdGpio::OUTPUT)  # RS
    @gpio.set(RESET, 1)
    reset()
    usleep(100)
    write_cmd([0x11])
    usleep(100)
    write([0xB1], [0x01, 0x2C, 0x2D])
    write([0xB2], [0x01, 0x2C, 0x2D])
    write([0xB3], [0x01, 0x2C, 0x2D, 0x01, 0x2C, 0x2D])
    write([0xB4], [0x07])
    write([0xC0], [0xA2, 0x02, 0x84])
    write([0xC1], [0xC5])
    write([0xC2], [0x0A, 0x00])
    write([0xC3], [0x8A, 0x2A])
    write([0xC4], [0x8A, 0xEE])
    write([0xC5], [0x0E])
    write([0x36], [0xC8])
    write([0xE0], [0x02, 0x1C, 0x07, 0x12, 0x37, 0x32, 0x29, 0x2D, 0x29, 0x25, 0x2B, 0x39, 0x00, 0x01, 0x03, 0x10])
    write([0xE1], [0x03, 0x1D, 0x07, 0x06, 0x2E, 0x2C, 0x29, 0x2D, 0x2E, 0x2E, 0x37, 0x3F, 0x00, 0x00, 0x02, 0x10])
    write([0x2A], [0x00, 0x02, 0x00, 0x81])
    write([0x2B], [0x00, 0x01, 0x00, 0xA0])
    write([0x3A], [0x05])
    write_cmd([0x29])
  end

  def reset()
    @gpio.set(RESET, 0)
    usleep(100)
    @gpio.set(RESET, 1)
    usleep(100)
  end

  def write_cmd(a)
    @gpio.set(RS, 0)
    @spi.transfer(a, 0)
  end

  def write_data(a)
    @gpio.set(RS, 1)
    @spi.transfer(a, 0)
  end

  def write(c, d)
    write_cmd(c)
    write_data(d)
  end

  def write_rgb(r, g, b)
    write_data([r & 0xF8 | g >> 5, g & 0xFC << 3 | b >> 3])
  end

  def fill(r, g, b)
    write([0x2A], [0x00, 0x02, 0x00, 0x81])
    write([0x2B], [0x00, 0x01, 0x00, 0xA0])
    write_cmd([0x2C])
    for i in 1..160 do
      for n in 1..128 do
        write_rgb(r, g, b)
      end
    end
  end
end

lcd = ST7735.new()

lcd.write_cmd([0x2C])
lcd.fill(0, 0, 0)

for i in 1..160 do
  for n in 1..128 do
    if i < 22 then
      lcd.write_rgb(0xFF, 0xFF, 0xFF) # White
    elsif i < 44 then
      lcd.write_rgb(0xFF, 0xFF, 0x00) # Yellow
    elsif i < 66 then
      lcd.write_rgb(0x00, 0xFF, 0xFF) # Cyan
    elsif i < 88 then
      lcd.write_rgb(0x00, 0xFF, 0x00) # Green
    elsif i < 110 then
      lcd.write_rgb(0xFF, 0x00, 0xFF) # Magenta
    elsif i < 132 then
      lcd.write_rgb(0xFF, 0x00, 0x00) # Red
    else
      lcd.write_rgb(0x00, 0x00, 0xFF) # Blue
    end
  end
end

今のところ画面全体の表示に5分くらいかかってしまい、実用になりません。。。oz_

追記:gpiospiのwaitをなくして、1K単位でのブロック転送にしたところ3秒くらいで表示できるようになりました。

追記:ユニバーサル基板を切って、シールドっぽくしてみました。