M5atom LITEに丸型液晶を繋いで表示させてみる

# はじめに
丸型液晶モジュールを手に入れたので、ディスプレイのないM5atomLITEに繋いでみました。
lovyanGFXで外付け液晶に表示させるための設定方法もメモしておきたいと思います。

:::note warn
コード中のピン22,23の設定が間違っていたので訂正しました。(2022 8.14)
誤 SCLK 22 -> 正　SCLK 23
誤 RST  23 -> 正  RST  22
:::
## M5atomLITEにLCDを接続する
今回手に入れたLCDモジュールはこれ。

https://www.waveshare.com/wiki/1.28inch_LCD_Module

ドライバはGC9A01。LovyanGFXでサポートされているドライバです。（[GitHub](https://github.com/lovyan03/LovyanGFX)で確認しました）
LCDモジュールは色々種類があって、買ってみたはいいけど動かないとかなったら悲しいので、対応したライブラリがあるか確認は大事です。まあAruduino対応とか書いてあれば大抵大丈夫みたいですが。

実は「lovyanGFX GC9A01」で検索すると、今回手に入れたのと似た別のLCDモジュールの例がいくつも出てきます。これ写真を見るとわかるんですが、液晶は同じでもピンの配置も名前も今回手に入れたものとは違うんです。
ピンの名前くらい全部共通にしておいてくれればいいのに！どうせなら配列も同じにしておいてほしい！そうすればサンプルコピペで使えるのに！

ぷりぷり腹を立てながら調べてみたところ、どうやらここのユーザー設定例を参考に、自分でピンの番号などを指定する必要があるという事が分かりました。
[lovyanGFX 2_user_setting.ino GitHub](https://github.com/lovyan03/LovyanGFX/blob/master/examples/HowToUse/2_user_setting/2_user_setting.ino)


lovyan03さんがサポートしているならいけるに違いない。うん。
データは[メーカーのサポートwiki](https://www.waveshare.com/wiki/1.28inch_LCD_Module)に詳細に書かれていて助かる。

接続はSPI接続…… **聞いたことはあります** 。
(この記事はこういうレベルの人が書いています)

### SPIのピンの接続

LCDモジュール側
| PIN  | Description       |
|------|-------------------|
| VCC  | 3.3V/5V |
| GND  | Ground |
| DIN  | SPI data input |
| CLK  | SPI clock input |
| CS   | Chip selection |
| DC   | Data/Command control |
| RST  | Reset |
| BL   | Backlight |

DIN,CLK,CS……。要するにあれでしょ、同じ名前のピンをマイコンと繋いでいけばいいんだよね？（ **初心者的理解** ）
M5atom側のピン配置を見てみると、

https://github.com/m5stack/M5Atom

M5ATOM側
| SPI  | PIN |
|------|-----|
| MOSI | G19 |
| CLK  | G23 |
| MISO | G33 |


……あ、あれ？ピン３つしかない。DINとかDCとかRSTとか、無いよ？
CLKはあるけど、MISOとかMOSIとか知らない名前が増えてるし。
LCDにはそんな名前なかったよね…？
わかりません！教えて偉い人！

https://lang-ship.com/blog/work/m5stickc-spi/

おお…疑問の答えがすべて書いてある。ありがたし。
それじゃとりあえず繋いで、試行錯誤してみましょうか。一回で上手くいくわけないし。

……と、その前に、lovyanGFXの設定が何やら必要だったはず。

### lovyanGFXへの対応

ということで、改めてこちらを見てみます。
[lovyanGFX 2_user_setting.ino GitHub](https://github.com/lovyan03/LovyanGFX/blob/master/examples/HowToUse/2_user_setting/2_user_setting.ino)

設定できる項目がたくさんありますし、「独自の設定をするならヘッダファイルにして保存推奨」とかあるのですが **まずはとにかく表示をさせてみたいよね？** 

ということで編集したものがこちらになります。

```
class LGFX : public lgfx::LGFX_Device
{
lgfx::Panel_GC9A01      _panel_instance;
lgfx::Bus_SPI       _bus_instance;   // SPIバスのインスタンス

public:

  LGFX(void)
  {
    { // バス制御の設定
      auto cfg = _bus_instance.config();    // バス設定用の構造体を取得します。
// SPIバスの設定
      cfg.spi_host = VSPI_HOST;     // 使用するSPIを選択  ESP32-S2,C3 : SPI2_HOST or SPI3_HOST / ESP32 : VSPI_HOST or HSPI_HOST
      cfg.spi_mode = 0;             // SPI通信モードを設定 (0 ~ 3)
      cfg.freq_write = 40000000;    // 送信時のSPIクロック (最大80MHz, 80MHzを整数で割った値に丸められます)
      cfg.freq_read  = 16000000;    // 受信時のSPIクロック
      cfg.spi_3wire  = true;        // 受信をMOSIピンで行う場合はtrueを設定
      cfg.use_lock   = true;        // トランザクションロックを使用する場合はtrueを設定
      cfg.dma_channel = SPI_DMA_CH_AUTO; // 使用するDMAチャンネルを設定 (0=DMA不使用 / 1=1ch / 2=ch / SPI_DMA_CH_AUTO=自動設定)
      cfg.pin_sclk = 23;            // SPIのSCLKピン番号を設定
      cfg.pin_mosi = 19;            // SPIのMOSIピン番号を設定
      cfg.pin_miso = -1;            // SPIのMISOピン番号を設定 (-1 = disable)
      cfg.pin_dc   = 33;            // SPIのD/Cピン番号を設定  (-1 = disable)
      _bus_instance.config(cfg);    // 設定値をバスに反映します。
      _panel_instance.setBus(&_bus_instance);      // バスをパネルにセットします。
    }

    { // 表示パネル制御の設定
      auto cfg = _panel_instance.config();    // 表示パネル設定用の構造体を取得します。

      cfg.pin_cs           =    21;  // CSが接続されているピン番号   (-1 = disable)
      cfg.pin_rst          =    22;  // RSTが接続されているピン番号  (-1 = disable)
      cfg.pin_busy         =    -1;  // BUSYが接続されているピン番号 (-1 = disable)

      cfg.panel_width      =   240;  // 実際に表示可能な幅
      cfg.panel_height     =   240;  // 実際に表示可能な高さ
      cfg.offset_x         =     0;  // パネルのX方向オフセット量
      cfg.offset_y         =     0;  // パネルのY方向オフセット量
      cfg.offset_rotation  =     0;  // 回転方向の値のオフセット 0~7 (4~7は上下反転)
      cfg.dummy_read_pixel =     8;  // ピクセル読出し前のダミーリードのビット数
      cfg.dummy_read_bits  =     1;  // ピクセル以外のデータ読出し前のダミーリードのビット数
      cfg.readable         =  true;  // データ読出しが可能な場合 trueに設定
      cfg.invert           = false;  // パネルの明暗が反転してしまう場合 trueに設定
      cfg.rgb_order        = false;  // パネルの赤と青が入れ替わってしまう場合 trueに設定
      cfg.dlen_16bit       = false;  // 16bitパラレルやSPIでデータ長を16bit単位で送信するパネルの場合 trueに設定
      cfg.bus_shared       = false;  // SDカードとバスを共有している場合 trueに設定(drawJpgFile等でバス制御を行います)

      _panel_instance.config(cfg);
    }
    setPanel(&_panel_instance); // 使用するパネルをセットします。
  }
};
```

内容を説明しまう。
>サンプルから変更する必要のあった箇所のみ解説します。

まずはパネルの型にあったインスタンスの選択から。
今回ドライバがGC9A01なので、それにあったものにします。
```
//lgfx::Panel_GC9A01      _panel_instance;
...
  lgfx::Panel_ILI9341     _panel_instance;
```
GC9A01を選択するためにコメント解除。
ILI9341を選択していた行はコメントにするか消去します。
```
  lgfx::Panel_GC9A01      _panel_instance;
...
//lgfx::Panel_ILI9341     _panel_instance;
```

バックライト制御、タッチスクリーンの制御に関する部分は今回使わないので全部消去。
（必要なければ削除）と書いてあるので安心。

つぎ、大事なSPI関係です。
```
      cfg.pin_sclk = 18;            // SPIのSCLKピン番号を設定
      cfg.pin_mosi = 23;            // SPIのMOSIピン番号を設定
      cfg.pin_miso = 19;            // SPIのMISOピン番号を設定 (-1 = disable)
      cfg.pin_dc   = 27;            // SPIのD/Cピン番号を設定  (-1 = disable)
```
上の記述ををM5atomのピン配置に書き換えるのですが、 ここのポイントは**pin G33をD/Cに設定することです。MISOではありません。** MISOは-1にします。
モジュール側の要求にあうようにマイコン側を合わせるとかそういう感じなんだろうか。

```
      cfg.pin_sclk = 23;            // SPIのSCLKピン番号を設定
      cfg.pin_mosi = 19;            // SPIのMOSIピン番号を設定
      cfg.pin_miso = -1;            // SPIのMISOピン番号を設定 (-1 = disable)
      cfg.pin_dc   = 33;            // SPIのD/Cピン番号を設定  (-1 = disable)
```

そしてもう一か所、pin関係の設定項目があります。
```
      cfg.pin_cs           =    14;  // CSが接続されているピン番号   (-1 = disable)
      cfg.pin_rst          =    33;  // RSTが接続されているピン番号  (-1 = disable)
      cfg.pin_busy         =    -1;  // BUSYが接続されているピン番号 (-1 = disable)
```
これは次のように決めました。
```
      cfg.pin_cs           =    21;  // CSが接続されているピン番号   (-1 = disable)
      cfg.pin_rst          =    22;  // RSTが接続されているピン番号  (-1 = disable)
      cfg.pin_busy         =    -1;  // BUSYが接続されているピン番号 (-1 = disable)
```
このCSとRSTは別にこのピンでなければならないわけではなく、空いている他のピンでも設定さえちゃんとすれば動くみたいです。

>余談ですが、
CS(チップセレクト)というのは複数SPI接続しているときに必要になってくるもので、LCDしかSPI接続していない今回は関係ありません……だからといって **「それなら繋がずにほっといても同じことだよね」とか思ってどこにもつながずにいるとLCDに何も表示されないぞ！気をつけろ！** 
CSを0vにしないとモジュールが信号を受け取ってくれないので、CS用のピンに接続するかもしくはGNDに接続しとかなければならないみたいです。

>余談ですが、
このLCDモジュールにはバックライト制御のためのBLというピンも出ています。
が、今回使わないので繋いでいません。（こっちは接続しなくてもOK）

最後にパネルの解像度を設定します。
このパネルは縦横240×240ドットという事なのでそのように。
(実際の表示範囲は240×240の正方形の内接円の範囲になります)
あと、パネルの明暗が反転してたのでコメントの指示通りcfg.invertをtrueに。
```
      cfg.panel_width      =   240;  // 実際に表示可能な幅
      cfg.panel_height     =   240;  // 実際に表示可能な高さ
　　　...
      cfg.invert           =  true;  // パネルの明暗が反転してしまう場合 trueに設定
```
これで最低限LCDに表示ができるようになりました。

## スケッチへの追加

準備ができたので、ようやくスケッチに組み込んで使ってみたいと思います。
lovyanGFXには丸形液晶用のサンプルがあります。さすが手厚い。
[ClockSample GitHub](https://github.com/lovyan03/LovyanGFX/tree/master/examples/Sprite/ClockSample)

このサンプルの次の部分に、先程書いた設定をコピペします。
```
#define LGFX_USE_V1
#include <LovyanGFX.hpp>
//ここにコピペ
```
これで完成！

## 実行結果

https://twitter.com/sullblue/status/1525126675528548352

設定を色々試して、とりあえず反転表示のほうが見た目が好みだったので反転表示にしました。
液晶が丸形というだけでなんかいい雰囲気ですね。
どのように使うか、使い方を考えるのが楽しみです。