ESP32で1.6インチのカラーLCD(130×130ピクセル、SSD1283A)に表示する



***目次***
［１］プロローグ
［２］SSD1283Aライブラリのインストール
［３］配線はどうするの？
［４］プログラムはどうするの？
［５］エピローグ
［６］関連記事

### ［１］プロローグ
前回、BME680センサの測定値を0.96インチ／1.3インチの2つのOLED（何れも128×64ドット）に表示するシステムを製作しました。***1.3インチは0.96インチより少し大きいだけですが見易くて良い***ことを実感しました。

今回は、1.6インチとさらに大きく且つ***カラー表示***（65K色）のグラフィックディスプレイに挑戦します。OLED ではなく、130×130ドット正方形のLCD（Liquid Crystal Display 液晶表示器）、インタフェースはSPIです。これをESP32で制御、開発環境はArduino (C, C++) です。
![OLED2個とLCD２small.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1834831/4cb18f59-2ab6-0266-594f-b4aab2b3cb3e.jpeg)
左から、1.6インチLCD、0.96インチOLED、1.3インチOLED。

### ［２］SSD1283Aライブラリのインストール
最初にやるべきことはライブラリのインストールです。Arduino IDE の「ツール」⇒「ライブラリを管理」⇒「ライブラリマネージャ」の検索窓で「SSD1283A」と入力し「GFX Library for Arduino」が表示されたら「インストール」ボタンをクリックします。

（余談：GFX ってこれまで、***じーえふえっくす***と発音してたけど、***グラフィックス***の略なんだな、と気が付きました）
![SSD1283Aライブラリを検索.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1834831/31af9107-6b93-a13d-a343-ef4f2c142dc1.jpeg)

### ［３］配線はどうするの？
配線方法を考える前にSPIの基本を少しだけおさらい。

SPIインタフェースは、I2Cに比べ配線の本数が少し多いけど速度が速いという特徴があります。
I2Cの信号線は、SCK（クロック）,SDA（データ）の2本で2線式インタフェースとも呼ばれますが、SPIはMOSI, MISO, SCLK, CSの4線式インタフェースです。
MOSIは「Master Out, Slave In」の略、MISOは「Master IN, Slave Out」の略です。
![もし味噌関係図.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1834831/3452771b-116b-9d82-bd43-242079a1d9ac.jpeg)
Master（ご主人様）はマイコン、Slave（奴隷）はLCD。　MOSIという信号線は、ご主人様が「おい、このデータを表示しろ」と送信し、「ははぁ承知いたしやした」と奴隷が受信する。MISOは、その逆方向のデータを伝送するための信号線です。この「もし味噌」の意味を理解していると配線やデバッグの際に役立ちます。

今回使用する1.6インチLCDモジュールには8個の端子があります。
![1_6インチカラーLCD2..jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1834831/b427971e-ebae-56aa-47f6-f0117fb49d90.jpeg)
***モジュールの仕様書とSSD1283Aのデータシート等***は、下記ページの「Product Documentation」の項にリンクがあります。

http://www.lcdwiki.com/1.6inch_SPI_Module_SSD1283A_SKU:MSP1601

上記8個の端子をESP32とどのように接続するのか？　答えはサンプルのスケッチの中に書いてありました。
![SSD1283Aスケッチ例.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1834831/1f477042-848b-f6d6-ebc6-caaf455c5c99.jpeg)
「ファイル」⇒「スケッチ例」⇒「GFX Library for Arduino」で色々なサンプルがあります。ImgViewerとかWiFiPhotoFrame という興味深いものがありますね。これは後の楽しみに残しておいて、まずは簡単そうな AsciiTables というスケッチを覗いてみましょう。

最初の方に各種マイコンボードとのピン接続のリストがあります。
```C++:ピン接続のリスト
/*******************************************************************************
 * Start of Arduino_GFX setting
 * 
 * Arduino_GFX try to find the settings depends on selected board in Arduino IDE
 * Or you can define the display dev kit not in the board list
 * Defalult pin list for non display dev kit:
 * Arduino Nano, Micro and more: CS:  9, DC:  8, RST:  7, BL:  6, SCK: 13, MOSI: 11, MISO: 12
 * ESP32 various dev board     : CS:  5, DC: 27, RST: 33, BL: 22, SCK: 18, MOSI: 23, MISO: nil
 * ESP32-C3 various dev board  : CS:  7, DC:  2, RST:  1, BL:  3, SCK:  4, MOSI:  6, MISO: nil
 * ESP32-S2 various dev board  : CS: 34, DC: 35, RST: 33, BL: 21, SCK: 36, MOSI: 35, MISO: nil
 * ESP32-S3 various dev board  : CS: 40, DC: 41, RST: 42, BL: 48, SCK: 36, MOSI: 35, MISO: nil
 * ESP8266 various dev board   : CS: 15, DC:  4, RST:  2, BL:  5, SCK: 14, MOSI: 13, MISO: 12
 * Raspberry Pi Pico dev board : CS: 17, DC: 27, RST: 26, BL: 28, SCK: 18, MOSI: 19, MISO: 16
 * RTL8720 BW16 old patch core : CS: 18, DC: 17, RST:  2, BL: 23, SCK: 19, MOSI: 21, MISO: 20
 * RTL8720_BW16 Official core  : CS:  9, DC:  8, RST:  6, BL:  3, SCK: 10, MOSI: 12, MISO: 11
 * RTL8722 dev board           : CS: 18, DC: 17, RST: 22, BL: 23, SCK: 13, MOSI: 11, MISO: 12
 * RTL8722_mini dev board      : CS: 12, DC: 14, RST: 15, BL: 13, SCK: 11, MOSI:  9, MISO: 10
 * Seeeduino XIAO dev board    : CS:  3, DC:  2, RST:  1, BL:  0, SCK:  8, MOSI: 10, MISO:  9
 * Teensy 4.1 dev board        : CS: 39, DC: 41, RST: 40, BL: 22, SCK: 13, MOSI: 11, MISO: 12
 ******************************************************************************/
```
"ESP" の文字を含むものが複数あるけど ESP32S には「ESP32 various dev board」でいいのかな？
取り敢えずこれで試してみよう・・・  

| CS | DC |RST | BL| SCK |MOSI|MISO|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|  5 | 27 | 33 | 22 | 18 | 23 | nil |

1.6インチLCDモジュールには下記8個のピンがありますが、上記リストの信号名と一致しません。
|LCDのピン||
|:-:|:-:|
|(1) VCC|電源3.3V～5V |
|(2) GND|グラウンド  |
|(3) CS|Chip Select  |
|(4) RST|リセット   |
|(5) A0|register/data select|
|(6) SDA|データ|
|(7) SCK|クロック|
|(8) LED| |

これらをどう接続するのか？　検索したけど見当たらず。自力で試行錯誤するしかない。
まずは、信号名が同じものから・・
・CS:5 ⇔ (3)CS
・RST:33 ⇔ (4)RST
・SCK:18 ⇔ (7)SCK

・MOSI:23 は「Master Out, Slave In」で ESP32：送信／LCD：受信のデータだなという訳で(6)SDA と接続。
・MISO:nil は「Master IN, Slave Out」だけど、LCDはデータを受信するだけで自分からMasterにデータを送信することは無いので nil（未使用の意味？）かな？
・BL:22 は、Back Light の略のようだから、(8)LEDに接続。
・残ったDC:27は (5)A0に接続。DCはData/Commandの選択という意味のようです。

まとめると以下のようになります。
|LCD| |ESP32|GPIO|
|:-:|:-:|:-:|:-:|
|(1) VCC|電源3.3V～5V|VCC|   |
|(2) GND|グラウンド|GND|   |
|(3) CS |Chip Select|CS|5|
|(4) RST|リセット|RST|33|
|(5) A0 |register/data select|DC|27|
|(6) SDA|データ|MOSI|23|
|(7) SCK|クロック|SCK|18|
|(8) LED|Back Light|BL|22|

ここで問題発生！　ESP32Sは幅が広いため5穴のブレッドボードだと何れか一方の側のピンしか使用できませ～ん。そこでGPIO33／GPIO27は、GPIO21／GPIO19に変更します。
|LCD| |ESP32|GPIO|
|:-:|:-:|:-:|:-:|
|(1) VCC|電源3.3V～5V|VCC| |
|(2) GND|グラウンド|GND| |
|(3) CS |Chip Select|CS|5|
|(4) RST|リセット|RST|21|
|(5) A0 |register/data select|DC|19|
|(6) SDA|データ|MOSI|23|
|(7) SCK|クロック|SCK|18|
|(8) LED|Back Light|BL|22|

![1_6インチLCDとESP32S接続図.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1834831/1eb87305-37d8-e033-c1d4-9d872a680f32.jpeg)
![1_6インチLCDとESP32S実体配線図.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1834831/7e68e71b-d3cf-5dcc-0a76-390955e0f3b8.jpeg)

SSD1283A搭載の1.6インチLCDモジュールの Fritzing のデータは検索しても見つかりませんでした。
~~これを作成する のはチョー面倒くさそうなのでいつものように画像処理ソフトで写真を貼り付けるだけで何とかごまかしました。~~
これを作成することに挑戦しようと思っていますが、取り敢えず今回は画像処理ソフトで写真を貼り付けるという方法で対処しました。








### ［４］プログラムはどうするの？
SSD1283Aライブラリが提供するサンプルの中から、まずは AsciiTables というスケッチを試してみました。名称から想像するとASCIIコードの一覧表でしょうか。

スケッチ例は、そのままでは動作しません。最初の方に以下のような記述があります。使用するボードに合わせて3か所カスタマイズする必要があります。

***［注！　カスタマイズする前に］***
　オリジナルには手を付けずに残しておきましょう。コピーして別名にしたものを編集しましょう。
　（私はうっかりオリジナルを改変してしまった・・）

```C++:カスタマイズ
/* More dev device declaration: https://github.com/～～～
　（省略）
/* More data bus class: https://github.com/～～～
　（省略）
/* More display class: https://github.com/～～～
　（省略）
```
上記のURLをクリックするとジャンプします。ジャンプ先のサイトに複数の候補があり、自分のシステムに最適と思うものを選んでコピーし、オリジナルのコードを以下のように修正しました。

```C++:変更後のプログラム
/*
   ASCII Table
   Arduino_GFX using the 'classic' fixed-space bitmap font for Adafruit_GFX
   This font using CP437 encoding (Extended ASCII)
   https://en.wikipedia.org/wiki/Extended_ASCII
*/
/*******************************************************************************
 * Start of Arduino_GFX setting
 * 
 * Arduino_GFX try to find the settings depends on selected board in Arduino IDE
 * Or you can define the display dev kit not in the board list
 * Defalult pin list for non display dev kit:
 * Arduino Nano, Micro and more: CS:  9, DC:  8, RST:  7, BL:  6, SCK: 13, MOSI: 11, MISO: 12
 * ESP32 various dev board     : CS:  5, DC: 27, RST: 33, BL: 22, SCK: 18, MOSI: 23, MISO: nil
 * ESP32-C3 various dev board  : CS:  7, DC:  2, RST:  1, BL:  3, SCK:  4, MOSI:  6, MISO: nil
 * ESP32-S2 various dev board  : CS: 34, DC: 35, RST: 33, BL: 21, SCK: 36, MOSI: 35, MISO: nil
 * ESP32-S3 various dev board  : CS: 40, DC: 41, RST: 42, BL: 48, SCK: 36, MOSI: 35, MISO: nil
 * ESP8266 various dev board   : CS: 15, DC:  4, RST:  2, BL:  5, SCK: 14, MOSI: 13, MISO: 12
 * Raspberry Pi Pico dev board : CS: 17, DC: 27, RST: 26, BL: 28, SCK: 18, MOSI: 19, MISO: 16
 * RTL8720 BW16 old patch core : CS: 18, DC: 17, RST:  2, BL: 23, SCK: 19, MOSI: 21, MISO: 20
 * RTL8720_BW16 Official core  : CS:  9, DC:  8, RST:  6, BL:  3, SCK: 10, MOSI: 12, MISO: 11
 * RTL8722 dev board           : CS: 18, DC: 17, RST: 22, BL: 23, SCK: 13, MOSI: 11, MISO: 12
 * RTL8722_mini dev board      : CS: 12, DC: 14, RST: 15, BL: 13, SCK: 11, MOSI:  9, MISO: 10
 * Seeeduino XIAO dev board    : CS:  3, DC:  2, RST:  1, BL:  0, SCK:  8, MOSI: 10, MISO:  9
 * Teensy 4.1 dev board        : CS: 39, DC: 41, RST: 40, BL: 22, SCK: 13, MOSI: 11, MISO: 12
 ******************************************************************************/
#include <Arduino_GFX_Library.h>

#define GFX_BL DF_GFX_BL // default backlight pin, you may replace DF_GFX_BL to actual backlight pin

/* More dev device declaration: https://github.com/moononournation/Arduino_GFX/wiki/Dev-Device-Declaration */
#if defined(DISPLAY_DEV_KIT)
Arduino_GFX *gfx = create_default_Arduino_GFX();
#else /* !defined(DISPLAY_DEV_KIT) */

#define TFT_BL 22    // Back Light

/* More data bus class: https://github.com/moononournation/Arduino_GFX/wiki/Data-Bus-Class */
//Arduino_DataBus *bus = create_default_Arduino_DataBus();
//Arduino_DataBus *bus = new Arduino_ESP32SPI(27 /* DC */, 5 /* CS */, 18 /* SCK */, 23 /* MOSI */, GFX_NOT_DEFINED /* MISO */, VSPI /* spi_num */);
Arduino_DataBus *bus = new Arduino_ESP32SPI(19 /* DC */, 5 /* CS */, 18 /* SCK */, 23 /* MOSI */, GFX_NOT_DEFINED /* MISO */, VSPI /* spi_num */);

/* More display class: https://github.com/moononournation/Arduino_GFX/wiki/Display-Class */
//Arduino_GFX *gfx = new Arduino_ILI9341(bus, DF_GFX_RST, 0 /* rotation */, false /* IPS */);
//Arduino_GFX *gfx = new Arduino_SSD1283A(bus, 7 /* RST */, 0 /* rotation */);
//Arduino_GFX *gfx = new Arduino_SSD1283A(bus, 33 /* RST */, 0 /* rotation */);
  Arduino_GFX *gfx = new Arduino_SSD1283A(bus, 21 /* RST */, 0 /* rotation */);

#endif /* !defined(DISPLAY_DEV_KIT) */
/*******************************************************************************
 * End of Arduino_GFX setting
 ******************************************************************************/

void setup(void)
{
    gfx->begin();
    gfx->fillScreen(BLACK);

#ifdef GFX_BL
    pinMode(GFX_BL, OUTPUT);
    digitalWrite(GFX_BL, HIGH);
#endif

    gfx->setTextColor(GREEN);
    for (int x = 0; x < 16; x++)
    {
//      gfx->setCursor(10 + x * 8, 2);
        gfx->setCursor(10 + x * 7, 1);
        gfx->print(x, 16);
    }
//  gfx->setTextColor(BLUE);    // 青は見えない、写真写りが悪い
//  gfx->setTextColor(YELLOW);  // 黄色とか
    gfx->setTextColor(RED);     // 赤が良い
    for (int y = 0; y < 16; y++)
    {
//      gfx->setCursor(2, 12 + y * 10);
        gfx->setCursor(2,  9 + y *  8);
        gfx->print(y, 16);
    }

    char c = 0;
    for (int y = 0; y < 16; y++)
    {
        for (int x = 0; x < 16; x++)
        {
//          gfx->drawChar(10 + x * 8, 12 + y * 10, c++, WHITE, BLACK);
            gfx->drawChar(10 + x * 7,  9 + y *  8, c++, WHITE, BLACK);
        }
    }

    delay(5000); // 5 seconds
}

void loop()
{
}
```
前記3か所のカスタマイズに加え、2点変更しました。

***改良点１***
　オリジナルのコードでは、全てのASCIIコードが画面に収まりません。表示できるのは横方向は0～Eまで、縦方向は0～Bまでです。そこで桁、行とも隙間を2ドットから1ドットに変更したところ横方向は0～Fの全て、縦方向は0～Eの範囲を表示しました。

***改良点２***
　左側、縦方向に0～Fのラベルがありますが青は見えにくく、写真写りも悪い。黄色とか赤が良いです。
![IMG_20220918_105043.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1834831/eeb21245-49b7-c28a-b3db-9927b080b66d.jpeg)

### ［５］エピローグ

今回は珍しく割とスムーズに進行しました。既存のライブラリを使用し、そのサンプルプログラムを実行しただけなので当たり前といえば当たり前の話ですが・・。
今後の予定は、サンプルプログラムに面白そうなのがあるので、それらを試すことと、自分で何かを作る際にどんなライブラリ関数があり、どう使うのかを調べようと思います。

### ［６］関連記事
これまでにQiitaに投稿した記事です。

https://qiita.com/totuto/items/27b8b25eba047560ce0f

https://qiita.com/totuto/items/2f58c0ce6e950bbc2eae

https://qiita.com/totuto/items/bb24760538af63b56039

https://qiita.com/totuto/items/885ee3939d0a06c5edc4

https://qiita.com/totuto/items/81944426dc81ab4b7e57

https://qiita.com/totuto/items/2a8db63abd1d3c82880f

https://qiita.com/totuto/items/d3bc435d3d2f545c1c02