サインスマート 1.8″ TFT カラー LCD用のグラフィックライブラリの作成

Pyshon言語で使用できるサインスマート1.8″TFT カラーLCD用のグラフィックライブラリを作成します。サインスマート1.8″TFT カラーLCDは、Raspberry Pi 3とSPIで接続します。作成するグラフィックライブラリは、任意の色での描画を可能とし、描画できる図形を次に示します。

* 直線
* 四角形および四角形の塗りつぶし
* 円形および円形の塗りつぶし

#サインスマート 1.8″ TFT カラー LCDについて
今回使用するサインスマート1.8″TFT カラーLCDは、ebayから購入しました。

<div align="center" ><img src="https://qiita-image-store.s3.amazonaws.com/0/124811/ca92c33e-fbc5-a4fe-aab5-7e221ce5fc2d.jpeg"></div>

仕様は次の通りです。

* 1.8インチ、128×160解像度、SPI 接続対応
* IC はST7735R、18-bit色のディスプレイが可能です
* SDカードソケットも一個追加したので、画像保存などは楽です
* Arduino/UNO/MEGA/Raspberry Pi　対応
* サイズ: 5.00 x 3.4cm

Raspberry PI 3とサインスマート 1.8インチ LCDの接続は、SPIを使用します。Raspberry PI 3とサインスマート 1.8インチ LCD間の信号線の接続およびSPIの設定方法については、「[Raspberry PI 3でサインスマート 1.8″ LCDの表示](http://tomosoft.jp/design/?p=7944)」を参照してください。

#グラフィックライブラリの作成

サインスマート 1.8″ TFT カラー LCD用のグラフィックライブラリは、サインスマートLCDクラス「ST7735」とグラフィック基本クラス「Graphic」の2つのクラスから構成されます。このグラフィックライブラリを使用することで、サインスマート 1.8インチ LCD上に任意の色で直線、四角形、円が描画できます。また、四角形、円については任意の色で塗りつぶしが可能です。作成した各クラスのソースコードは、github「[サインスマート 1.8″ TFT カラー LCDグラフィックライブラリ](https://github.com/tomosoft-jp/SainSmartLcd.git)」から取得できます。

##サインスマートLCDクラス「ST7735」
サインスマートLCDクラス「ST7735」は、サインスマート 1.8″ LCDに実装されているLCDコントローラIC「ST7735R」に対して、制御レジスタやデータレジスタおよび描画用メモリに書き込むクラスです。ファイル名は、「ST7735.py」となります。PythonのRPi.GPIOパッケージを用いてGPIOのライトを行います。GPIO24は、レジスタ選択信号（0：制御用レジスタ、1：データレジスタ）「RS/DC」、	GPIO25は、LCDコントローラICのリセット信号「RES」を示します。PythonからSPIデバイスを操作するためにのpy-spidevを使用します。


1. インスタンス化するときに、サインスマート 1.8″ TFT カラー LCDの画面サイズをパラメータとして受け取ります。インスタンス化されたときに、次のコードでLCDコントローラIC「ST7735R」のリセット、py-spidevのインスタンス化およびオープン、LCDコントローラIC「ST7735R」のレジスタ設定などを行います。なお、LCDコントローラIC「ST7735R」の設定については、「[262K Color Single-Chip TFT Controller/Driver](https://cdn-shop.adafruit.com/datasheets/ST7735R_V0.2.pdf)」を参照してください。

```python
 self.width = width
 self.height = height
 self.BMPData = 0xf000 * [0xfffff]

 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)

 # reset
 GPIO.output(25, False)
 time.sleep(0.1)
 GPIO.output(25, True)
 time.sleep(0.1)

 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))
 # 電源設定（PWCTR1～3）
 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_cmd(0x20)
 # ガンマ設定
 self.write(
     (0xE0, 0x0F, 0x1A, 0x0F, 0x18, 0x2F, 0x28, 0x20, 0x22, 0x1F, 0x1B, 0x23, 0x37, 0x00, 0x07, 0x02, 0x10))
 self.write(
     (0xE1, 0x0F, 0x1B, 0x0F, 0x17, 0x33, 0x2C, 0x29, 0x2E, 0x30, 0x30, 0x39, 0x3F, 0x00, 0x07, 0x03, 0x10))
 self.write_cmd(0x29)
 self.write_cmd(0x13)
 # 液晶描画方向設定 縦長 0x40 横長0x20
 self.write((0x36, 0x40))
 # 描画エリア設定 0～BMPのサイズ
 self.write((0x2A, 0x00, 0x00, 0x00, self.width))
 self.write((0x2B, 0x00, 0x00, 0x00, self.height))
 self.write((0x3A, 0x06))
 # 表示RAM転送モードに設定
 self.write_cmd(0x2C)
```

2.　write_cmdメソッドは、コマンドレジスタにパラメータで与えられた値を、xfer2メソッドで書き込みます。
3. write_dataメソッドは、データレジスタにパラメータで与えられた値を、xfer2メソッドで書き込みます。
4. writeメソッドは、コマンドレジスタにパラメータで与えられた最初の値を、xfer2メソッドで書き込みます。次に、データレジスタにパラメータで与えられた残りの値を、xfer2メソッドで書き込みます。
5. dotメソッドは、指定されたｘ、ｙ位置に対応する描画メモリ位置を計算し、その描画メモリ位置にパラメータで与えられたカラーコード（18ビット）を設定します。
6. sendbufメソッドは、作成した描画メモリの内容を、xfer2メソッドで書き込みます。

##グラフィック基本クラス「Graphic」
グラフィック基本クラス「Graphic」は、グラフィックの基本図形（直線、四角形、円形）を描画するクラスで、ファイル名は、「Graphic.py」となります。インスタンス化するときに、サインスマートLCDクラス「ST7735」のインスタンスをパラメータとして受け取ります。この情報を使って、サインスマート 1.8″ TFT カラー LCDの画面サイズを取得し、dotメソッドを呼び出します。また、各メソッドは、パラメータで指定された位置について、エラーチェックを行い、サインスマート 1.8″ TFT カラー LCDの画面サイズの外側を指定している場合は、エラーメッセージを表示します。

1. drawlineメソッドは、与えられた始点と終点の間に連続した点を置き、近似的な直線を引くためのアルゴリズム「ブレゼンハムのアルゴリズム」を使用します。

```python
if (x0p >= self._st7735.width) or (y0p >= self._st7735.height):
    print " drawline x0, y0 Range error"
    return
if (x1p >= self._st7735.width) or (y1p >= self._st7735.height):
    print " drawline x1, y1 Range error"
    return
x0 = x0p
y0 = y0p
x1 = x1p
y1 = y1p

steep = abs(y1 - y0) > abs(x1 - x0)
if steep:
    x0, y0 = y0, x0
    x1, y1 = y1, x1
if x0 > x1:
    x0, x1 = x1, x0
    y0, y1 = y1, y0
dx = x1 - x0
dy = abs(y1 - y0)
err = dx / 2
ystep = -1
if y0 < y1:
    ystep = 1
for xx0 in range(x0, x1):
    if steep:
        self._st7735.dot(y0, xx0, color)
    else:
        self._st7735.dot(xx0, y0, color)
    err -= dy
    if err < 0:
        y0 += ystep
        err += dx
```

2.　drawrectメソッドは、drawlineメソッドを使用して描画します。
3. fillrectメソッドは、dotメソッドを使用して、指定された位置から、指定された幅と高さの領域を指定された色で塗りつぶします。
4. fillscreenメソッドは、サインスマート 1.8″ TFT カラー LCDの画面サイズをパラメータに、fillrectメソッドを呼び出します。
5. drawcircleメソッドは、処理時間を節約するために、円を描画する関数は、x'=-y, y'=xという微分公式を利用し、円形の対称性を利用して、円周上の座標を八分の一だけを計算します。
 
```python
f = 1 - r
ddf_x = 1
ddf_y = -2 * r
x = 0
y = r
self._st7735.dot(x0, y0 + r, color)
self._st7735.dot(x0, y0 - r, color)
self._st7735.dot(x0 + r, y0, color)
self._st7735.dot(x0 - r, y0, color)

while x < y:
    if f >= 0:
        y -= 1
        ddf_y += 2
        f += ddf_y

    x += 1
    ddf_x += 2
    f += ddf_x

    self._st7735.dot(x0 + x, y0 + y, color)
    self._st7735.dot(x0 - x, y0 + y, color)
    self._st7735.dot(x0 + x, y0 - y, color)
    self._st7735.dot(x0 - x, y0 - y, color)
    self._st7735.dot(x0 + y, y0 + x, color)
    self._st7735.dot(x0 - y, y0 + x, color)
    self._st7735.dot(x0 + y, y0 - x, color)
    self._st7735.dot(x0 - y, y0 - x, color)
 ```

6.　drawcirclehelperメソッドは、角の丸みを描画します。
7. fillcirclehelperメソッドは、角の丸みを塗りつぶします。
8. fillcircleメソッドは、drawlineメソッドで直線を縦に引き、fillcirclehelperメソッドで半円を塗りつぶします。

#グラフィックライブラリの実行
作成したグラフィックライブラリを使用したサンプルコードを次に示します。サインスマート 1.8″ TFT カラー LCD上に、一本の直線、二個の円形（一個は塗りつぶし）、二個の四角形（一個は塗りつぶし）を描画します。

```python
    ST7735_TFTWIDTH = 128
    ST7735_TFTHEIGHT = 160

    ST7735_BLACK = 0x0000
    ST7735_BLUE = 0x0000FF
    ST7735_RED = 0xFF0000
    ST7735_GREEN = 0x008000
    ST7735_CYAN = 0x00FFFF
    ST7735_MAGENTA = 0xFF00FF
    ST7735_YELLOW = 0xFFFF00
    ST7735_WHITE = 0xFFFFFF

    st7735 = ST7735(ST7735_TFTWIDTH, ST7735_TFTHEIGHT)
    graphic = Graphic(st7735)
    try:
        graphic.fillscreen(ST7735_RED)
        graphic.drawline(10, 10, ST7735_TFTWIDTH - 10, ST7735_TFTHEIGHT - 10, ST7735_BLACK)
        graphic.drawrect(0, 40, 20, 40, ST7735_CYAN)
        graphic.fillrect(80, 60, 40, 20, ST7735_YELLOW)
        graphic.drawcircle(64, 40, 15, ST7735_MAGENTA)
        graphic.fillcircle(64, 120, 30, ST7735_GREEN)
        st7735.sendbuf()

    except KeyboardInterrupt:
        print '\nbreak'
        # GPIO.cleanup()
```

1. 各クラスをインスタンス化します。サインスマートLCDクラス「ST7735」のインスタンス化では、ドットで示す画面サイズをパラメータで与えます。グラフィック基本クラス「Graphic」のインスタンス化では、サインスマートLCDクラス「ST7735」のインスタンスをパラメータで与えます。
2. カラーコードは、RGBのそれぞれ8ビットで与えます。
2. fillscreenメソッドで、サインスマート 1.8″ TFT カラー LCDの画面を赤で塗りつぶします。
3. drawlineメソッドで、黒の直線を描画します。
4. drawrectメソッドで、シアンの四角形を描画します。
5. fillrectメソッドで、黄色の四角形を塗りつぶします。
6. drawcircleメソッドで、マゼンタで円形を描画します。
7. fillcircleメソッドで、緑で円形を塗りつぶします。
8. sendbufメソッドで、描画データをサインスマート 1.8″ TFT カラー LCDに送信します。

このコードを実行すると、サインスマート 1.8″ TFT カラー LCDに次の図形が表示されます。
<div align="center" ><img src="https://qiita-image-store.s3.amazonaws.com/0/124811/bf58b08e-027e-683d-6954-390036267576.jpeg"></div>