pico-jxblib と TFT LCD の話

[**pico-jxglib**](https://qiita.com/ypsitau/items/ca5fb14f0bda56e84486) は、ワンボードマイコン Raspberry Pi Pico の Pico SDK プログラミングをサポートするライブラリです。

前の記事では、このライブラリの概要と導入方法について説明しました。

https://qiita.com/ypsitau/items/ca5fb14f0bda56e84486

今回は、**pico-jxglib** を使って TFT LCD の描画をします。

## TFT LCD について

CPU に接続する周辺機器で一番遊び心をくすぐるのはディスプレイ関連ではないでしょうか。実用面においても、文字やグラフィックなどユーザに伝達できる情報量はピカイチです。数あるディスプレイの中でも、ワンボードマイコンに SPI インターフェースで接続できる TFT LCD は、コンパクトなサイズと手ごろな価格で非常に魅力的なデバイスです。

ところで、僕は電子部品の調達に主に秋月電子と Amazon を利用しているのですが、これらのショップで「TFT LCD」というキーワードで検索して見つけた以下のデバイスを購入しました。

- **ST7789**
  左のデバイスが 1.8 インチ・ピクセル数 240x320、右が 1.3 インチ・ピクセル数 240x240 です。それぞれ 1,000 円程度で購入できます
  ![ST7789.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48975/d86fa75f-2135-4360-5579-b789b937b45e.jpeg)
- **ST7735**
  左のデバイスが 0.96 インチ・ピクセル数 80x160、右が 1.8 インチ・ピクセル数 128x160 です。それぞれ 1,000 円未満で購入できます。
  ![ST7735.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48975/8fb249fb-5f2b-1aab-00fc-390b43eeae2b.jpeg)
- **ILI9341/ILI9488**
  タッチスクリーン付きのデバイスです。左が ILI9341 で 2.8 インチ・ピクセル数 240x320、右が ILI9488 で 3.5 インチ・ピクセル数 320x480 です。値段はそれぞれ 1,500 円、2,500 円程度です
  ![ILI9341_ILI9488.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48975/d7e87357-e3ff-794a-c0fb-1bd44d43b629.jpeg)

上に挙げたデバイスたちは、初期化に必要な手順や VRAM の描画方向、ピクセルフォーマットなどに若干の違いはありますが、コマンドはほぼ共通しています。今回の記事では、**pico-jxglib** でこれらのデバイスに画像データや文字を描画します。

## 準備するもの

Visual Studio Code や Pico SDK のセットアップが済んでいない方は [「Pico SDK ことはじめ」](https://qiita.com/ypsitau/items/afd020cad554910a6a9e#%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83) をご覧ください。

GitHub から **pico-jxglib** をクローンします。

```
git clone https://github.com/ypsitau/pico-jxglib.git
cd pico-jxglib
git submodule update --init
```

**pico-jxglib** はほぼ毎日更新されています。すでにクローンしている場合は、`pico-jxglib` ディレクトリで以下のコマンドを実行して最新のものにしてください。

```
git pull
```

## TFT LCD の描画

### ST7789 の接続

デバイス **ST7789 (ピクセル数 240x320)** を接続して描画処理をします。

ブレッドボードの配線イメージは以下の通りです。

![circuit-st7789.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48975/27efe0af-fbb0-cb40-1c48-bffa7e2e7d0c.png)

VSCode のコマンドパレットから `>Raspberry Pi Pico: New Pico Project` を実行し、以下の内容でプロジェクトを作成します。Pico SDK プロジェクト作成の詳細や、ビルド、ボードへの書き込み方法については[「Pico SDK ことはじめ」](https://qiita.com/ypsitau/items/afd020cad554910a6a9e#%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AE%E4%BD%9C%E6%88%90) を参照ください。

- **Name** ... プロジェクト名を入力します。今回は例として `lcdtest` を入力します
- **Board type** ... ボード種別を選択します
- **Location** ... プロジェクトディレクトリを作る一つ上のディレクトリを選択します
- **Stdio support** .. Stdio に接続するポート (UART または USB) を選択します
- **Code generation options** ... **`Generate C++ code` にチェックをつけます**

このプロジェクトディレクトリと `pico-jxglib` のディレクトリ配置が以下のようになっていると想定します。

```
+-[pico-jxglib]
+-[lcdtest]
  +-CMakeLists.txt
  +-lcdtest.cpp
  +- ...
```

`CMakeLists.txt` の最後に以下の行を追加してください。

```cmake:CMakeLists.txt
target_link_libraries(lcdtest jxglib_ST7789 jxglib_DrawableTest)

add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../pico-jxglib pico-jxglib)
```

ソースファイルを以下のように編集します。

```c++:lcdtest.cpp
#include <stdio.h>
#include "pico/stdlib.h"
#include "jxglib/ST7789.h"
#include "jxglib/DrawableTest.h"

using namespace jxglib;

int main()
{
	::stdio_init_all();
	::spi_init(spi1, 125 * 1000 * 1000);
	GPIO14.set_function_SPI1_SCK();
	GPIO15.set_function_SPI1_TX();
	ST7789 display(spi1, 240, 320, {RST: GPIO10, DC: GPIO11, CS: GPIO12, BL: GPIO13});
	display.Initialize(Display::Dir::Rotate0);
    DrawableTest::RotateImage(display);
	//DrawableTest::DrawString(display);
	//DrawableTest::DrawFonts(display);
}
```

`DrawableTest::` で始まる関数のコメントを外してプログラムを[ビルド・書き込み・実行](https://qiita.com/ypsitau/items/afd020cad554910a6a9e#%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%81%AE%E3%83%93%E3%83%AB%E3%83%89)してください。以下のような表示をします。

- `DrawableTest::RotateImage()` は LCD に画像データを回転して表示するテスト用関数です。UART につなげたシリアルターミナルから適当なキーを入力すると画像を 90 度ずつ回転して描画します。
![lcdtest-RotateImage.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48975/75e42075-c590-738f-11ae-c21b94e1489e.jpeg)

- `DrawablTest::DrawString()` は　LCD の画面いっぱいに日本語テキストを表示するテスト用関数です。UART につなげたシリアルターミナルで操作することで、フォント種別・フォントの描画倍率・行間隔を変えられます。
![lcdtest-DrawString.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48975/c323bdd7-a0d6-e1bc-96e7-336bddc20149.jpeg)

- `DrawablTest::DrawFonts()` は LCD に異なるフォントで文字列を表示するテスト用関数です。
![lcdtest-DrawFonts.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48975/80e3bcd1-e299-f084-6f8f-1fc8049748a2.jpeg)

### 他のデバイスの接続

ST7789 以外のデバイスを接続する場合、上に示したプロジェクトをもとにして以下のように変更します。

- **ST7789 (ピクセル数 240x240)**
  ブレッドボードの配線は上に示した ST7789 の図を参考にしてください。このデバイスには CS (Chip Select) がありません。ソースファイルの対応する行を以下のように変更します
  ```diff_cpp:lcdtest.cpp
  - ST7789 display(spi1, 240, 320, {RST: GPIO10, DC: GPIO11, CS: GPIO12, BL: GPIO13});
  + ST7789 display(spi1, 240, 240, {RST: GPIO10, DC: GPIO11, BL: GPIO13});
  ```

- **ST7735 (ピクセル数 80x160)**
  ブレッドボードの配線は上に示した ST7789 の図を参考にしてください。`CMakeLists.txt` とソースファイルの対応する箇所を以下のように変更します
  ```cmake:CMakeLists.txt
  target_link_libraries(lcdtest jxglib_ST7735 jxglib_DrawableTest)
  ```
  ```diff_cpp:lcdtest.cpp
  - #include "jxglib/ST7789.h"
  + #include "jxglib/ST7735.h"

  - ST7789 display(spi1, 240, 320, {RST: GPIO10, DC: GPIO11, CS: GPIO12, BL: GPIO13});
  + ST7735 display(spi1, 80, 160, {RST: GPIO10, DC: GPIO11, CS: GPIO12, BL: GPIO13});
  ```

- **ST7735 (ピクセル数 128x160)**
  ブレッドボードの配線は上に示した ST7789 の図を参考にしてください。`CMakeLists.txt` とソースファイルの対応する箇所を以下のように変更します
  ```cmake:CMakeLists.txt
  target_link_libraries(lcdtest jxglib_ST7735 jxglib_DrawableTest)
  ```
  ```diff_cpp:lcdtest.cpp
  - #include "jxglib/ST7789.h"
  + #include "jxglib/ST7735.h"

  - ST7789 display(spi1, 240, 320, {RST: GPIO10, DC: GPIO11, CS: GPIO12, BL: GPIO13});
  + ST7735::TypeB display(spi1, 128, 160, {RST: GPIO10, DC: GPIO11, CS: GPIO12, BL: GPIO13});
  ```

- **ILI9341**
  ブレッドボードの配線イメージは以下の通りです
![circuit-ili9341.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48975/c48e8af0-5a8e-df0d-dfdc-1e3fff1ff5b3.png)
  `CMakeLists.txt` とソースファイルの対応する箇所を以下のように変更します
  ```cmake:CMakeLists.txt
  target_link_libraries(lcdtest jxglib_ILI9341 jxglib_DrawableTest)
  ```
  ```diff_cpp:lcdtest.cpp
  - #include "jxglib/ST7789.h"
  + #include "jxglib/ILI9341.h"

  - ST7789 display(spi1, 240, 320, {RST: GPIO10, DC: GPIO11, CS: GPIO12, BL: GPIO13});
  + ILI9341 display(spi1, 240, 320, {RST: GPIO10, DC: GPIO11, CS: GPIO12, BL: GPIO13});
  ```

- **ILI9488**
  ブレッドボードの配線は上に示した ILI9341 の図を参考にしてください。`CMakeLists.txt` とソースファイルの対応する箇所を以下のように変更します
  ```cmake:CMakeLists.txt
  target_link_libraries(lcdtest jxglib_ILI9488 jxglib_DrawableTest)
  ```
  ```diff_cpp:lcdtest.cpp
  - #include "jxglib/ST7789.h"
  + #include "jxglib/ILI9488.h"

  - ST7789 display(spi1, 240, 320, {RST: GPIO10, DC: GPIO11, CS: GPIO12, BL: GPIO13});
  + ILI9488 display(spi1, 320, 480, {RST: GPIO10, DC: GPIO11, CS: GPIO12, BL: GPIO13});
  ```

## 次回の記事

次回は「TFT LCD の話」の続きです。初期化処理の詳細や、描画機能について解説します。

https://qiita.com/ypsitau/items/6117e654e1f303e770f6