前回試してみたSPI接続カラーLCDへの画像ファイル表示。イメージ処理モジュールを利用して簡単に行う事ができたが、表示速度が思ったよりもかなり遅い。
これは1ピクセル単位でSPI通信を行っているため、オーバーヘッドが大きいのだろうと推測して、複数バイトをまとめて転送するように書き換えてみた。
spidevのxfer2は4096バイトまでまとめて転送できるようなので、画面の塗りつぶしは2048ピクセルの転送を10回、イメージの表示は128ピクセルの1ライン分を160回転送するようにした。プログラムは以下の通り。
#!/usr/bin/env python # -*- coding: utf-8 -*- import RPi.GPIO as GPIO import spidev # sudo pip install spidev import time import sys from PIL import Image # sudo pip install pillow class ST7735: def __init__(self): self.spi = spidev.SpiDev() self.spi.open(0, 0) self.spi.max_speed_hz = 16000000 GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) GPIO.setup(24, GPIO.OUT) GPIO.setup(25, GPIO.OUT) self.reset() self.write_cmd(0x11) time.sleep(0.12) self.write((0xB1, 0x01, 0x2C, 0x2D)) self.write((0xB2, 0x01, 0x2C, 0x2D)) self.write((0xB3, 0x01, 0x2C, 0x2D, 0x01, 0x2C, 0x2D)) self.write((0xB4, 0x07)) self.write((0xC0, 0xA2, 0x02, 0x84)) self.write((0xC1, 0xC5)) self.write((0xC2, 0x0A, 0x00)) self.write((0xC3, 0x8A, 0x2A)) self.write((0xC4, 0x8A, 0xEE)) self.write((0xC5, 0x0E)) self.write((0x36, 0xC8)) self.write((0xE0, 0x02, 0x1C, 0x07, 0x12, 0x37, 0x32, 0x29, 0x2D, 0x29, 0x25, 0x2B, 0x39, 0x00, 0x01, 0x03, 0x10)) self.write((0xE1, 0x03, 0x1D, 0x07, 0x06, 0x2E, 0x2C, 0x29, 0x2D, 0x2E, 0x2E, 0x37, 0x3F, 0x00, 0x00, 0x02, 0x10)) self.write((0x2A, 0x00, 0x02, 0x00, 0x81)) self.write((0x2B, 0x00, 0x01, 0x00, 0xA0)) self.write((0x3A, 0x05)) self.write_cmd(0x29) def reset(self): GPIO.output(25, False) time.sleep(0.1) GPIO.output(25, True) time.sleep(0.1) def write_cmd(self, cmd): GPIO.output(24, False) # RS=0 self.spi.xfer2([cmd]) def write_data(self, data): GPIO.output(24, True) # RS=1 self.spi.xfer2([data]) def write(self, cmd): if len(cmd) == 0: return GPIO.output(24, False) # RS=0 self.spi.xfer2([cmd[0]]) GPIO.output(24, True) # RS=1 self.spi.xfer2(list(cmd[1:])) def write_rgb(self, r, g, b): self.write_data(r & 0xF8 | g >> 5) self.write_data(g & 0xFC << 3 | b >> 3) def fill(self, r, g, b): self.write((0x2A, 0x00, 0x02, 0x00, 0x81)) self.write((0x2B, 0x00, 0x01, 0x00, 0xA0)) self.write_cmd(0x2C) GPIO.output(24, True) # RS=1 hi = r & 0xF8 | g >> 5 lo = g & 0xFC << 3 | b >> 3 pixline = [] for n in range(2048): pixline.append(hi) pixline.append(lo) for n in range(10): self.spi.xfer2(pixline[0:]) def image(self, file): try: im = Image.open(file).convert("RGB") im.thumbnail((128, 160)) pix = im.load() self.write((0x2A, 0x00, 0x02, 0x00, 0x81)) self.write((0x2B, 0x00, 0x01, 0x00, 0xA0)) self.write_cmd(0x2C) GPIO.output(24, True) # RS=1 pixline = [] for i in range(160): for n in range(128): pixel = pix[n, i] hi = pixel[0] & 0xF8 | pixel[1] >> 5 lo = pixel[1] & 0xFC << 3 | pixel[2] >> 3 pixline.append(hi) pixline.append(lo) self.spi.xfer2(pixline) del pixline[:] except: pass if __name__ == "__main__": lcd = ST7735() param = sys.argv t1 = time.clock() for n in range(100): lcd.fill(0, 0, 0) lcd.image(param[1]) t2 = time.clock() print 'processing time : ', str(t2 - t1) try: while True: pass except KeyboardInterrupt: print '\nbreak' GPIO.cleanup()
画面のクリアとイメージ表示を100回くり返すようにして、所要時間を旧バージョンと比べてみると、以下のようになった。
$ sudo python spilcd2.py Lenna.png
processing time : 36.28
$ sudo python spilcd.py Lenna.png
processing time : 283.74
結果は一目瞭然で、8倍近く高速化できた。
このぐらいの速度で表示できるのなら、Pythonだけでも何か実用性のある使い方ができるかも知れない。