M5StampS3に3.2インチLCD（ILI9341）をつけてみる

# はじめに

最近、M5Stack のプログラミングに興味を持ち始めたのですが、いかんせん ディスプレイ（2インチ）が小さくて、色々とツライお年頃なので、より大きな液晶で表示できるデバッグ環境を構築したいと考えました。

M5Stack には M5Stamp と呼ばれるコアチップ（SoC）のみ搭載した最小構成の製品があり、それと任意の（適度なサイズ感の）LCD を接続することで、目的とする環境を構築することができるようです。

ただ、当方は電子工作未経験なので「何から揃えて良いのやら」という状態でした。

幸い、MSX0Stampという、M5StackをベースにしたIoT用MSX（MSX0）のStamp版がもうすぐ登場するらしく、MSX-BBSの方に[そちら方面に詳しい方](https://twitter.com/chikuwa_empire)が居られたので、色々と教えて貰いながら組み立てにチャレンジしてみることにしました。

本書では、組み立てに必要だった部品・工具、組み立て手順と LCD に Hello World! を表示する制御プログラムを記述して安定動作させるまでの内容を、可能な限りローコンテキストで記します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2161417/cd068fbb-2475-e150-42d2-b5533bcddb42.png)

# 1. 部品調達

## 1-1. M5Stamp S3

https://www.marutsu.co.jp/pc/i/2719680/

コア部分です。

当初、M5Stamp Pico を導入予定でしたが、

- 音声出力に対応したかったので、DAC が付いている Pico の方が良いかと思ったが、スピーカーを調達するより I2S 接続の DAC 付きモジュールの方が入手しやすそうだった（というか試したかった）
- Pico は ESP32 ダウンローダーが別途必要（※Diy Kit を買えば一緒についてくる）らしいのですが、S3 なら最初っから ESP32 ダウンローダー相当の USB-C ポートが付いているので楽そうだった。

といった事情で、M5Stamp Pico → M5Stamp S3 に変更しました。

なお、給電の方は M5Stamp S3 の USB 端子から行うことができるらしいので、電源装置などを取り付ける必要は無いようです。

## 1-2. ブレッドボード

https://www.marutsu.co.jp/pc/i/14660/

当初、プリント基板を作成＆発注してICチップをはんだ付けしていくものかと思っていたのですが、ブレッドボードというジャンパー線の抜き差しだけ（はんだ不要）でICチップの接続ができる便利なものがあるらしいです。これなら、「M5StampS3が壊れた」とか「M5Stamp Picoを試してみたくなった」といった時にカジュアルにICチップが交換できるので便利そうです。


## 1-3. ブレッドボード用ジャンパー線

ブレッドボード上に配置した各種チップのポート同士を接続するケーブル（ジャンパー線）が必要です。

https://www.marutsu.co.jp/pc/i/69682/

なお、極性は3種類（♂♀、♂♂、♀♀）ありますが、何のことやらよく分からなかったので、とりあえず各30本づつ調達しておきました。

> 結果的に本書記述の内容なら、♂♀が10本あれば事足りるので、予算を抑えたい場合は♂♀を10本（1組）だけ購入すれば良さそうです。

## 1-4. LCD

M5Stack の液晶モジュールは `Ili9341` というもので、`4wire` の `SPI` というインタフェースで接続され、解像度は `QVGA (320x240)` で、対角線の長さが `2インチ (5.08cm)` です。

:::note warn
これは後になって気づいたのですが、最近の M5Stack の LCD モジュールは `Ili9341` ではなく `Ili9342C` のようです。本書はこのまま `Ili9341` で進めてしまいますが、これから新たに構築される方は `Ili9342C` を購入した方が良いかもしれません。（ただし、`Ili9342C` のディスプレイモジュールは Aliexpress でも現状見つからないので ILI9341 にせざるを得ないかもしれません）
:::

つまり、それと同じ __モジュール x インタフェース x 解像度__ の __より大きな液晶__ を調達すれば目的を果たせそうです。

在庫が見つかった最大サイズは 3.2インチ (8.128cm) でした。

2インチと3.2インチのサイズ感を比較すると、ざっくりこんな感じでしょうか...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2161417/bc80bc4d-bc35-fd8b-ad55-4cdb8cd53751.png)
> ※上記画像をパソコンにダウンロード & Previewなどで縮小して、「2インチ」の部分のサイズ感が実機（M5Stack）の液晶部分のサイズ感と一致するように調整すれば、そこそこ正確なサイズ感が分かると思われます。

なお、国内では通販で取り扱っている店が見当たらなかったので Aliexpress で調達しました。

以下の「Module with Touch」をチョイス

https://ja.aliexpress.com/item/1005003005413104.html

## 1-5. ハンダ一式

当初、ハンダ付けは不要だと思っていたのですが、M5Stampのピンヘッダーはハンダ無しだと電流が安定しなかったので、近所のホームセンターでハンダ一式を調達しました。とりあえず最低限以下の「電子部品用」のものがあれば大丈夫かなと思われます。

- ハンダゴテ ... 必須
- ハンダ ... 必須
- ハンダゴテ台 ... 必須
- フラックス ... スルーホールがかなり細かくショートする危険があるのでその防止の為
- ハンダ吸収線 ... もしも失敗（ショート）した時のための保険


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2161417/6671a1f9-c4fe-1b6c-ccc6-5a47932ce3e3.png)

## 1-6. 予算

### (1) 国内発注分（マルツオンライン）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2161417/9f4f00b3-3dc7-f652-2f17-4fc9ff229c13.png)
国内発注分の小計: `¥4,234` (送料無料)

### (2) 中国発注分（Aliexpress）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2161417/9fb4fee2-5ea3-6d34-68c4-0f240983981d.png)
中国発注分の小計: `¥1,590`

### (3) ホームセンターで調達分（カインズ）

|品目|メーカー|型式|税込み価格|
|:-|:-|:-|-:|
|ハンダゴテ|太洋電機産業|KS-30R|¥1,180|
|ハンダ|太洋電機産業|SE-06010|¥980|
|ハンダゴテ台|太洋電機産業|ST-11|¥980|
|フラックス（電気用）|太洋電機産業|BS-55|¥378|
|ハンダ吸収線|太洋電機産業|CP-2015|¥258|

ホームセンターの小計: `¥3,776`

### (4) 合計予算

```
¥4,234 + ¥1,590 + ¥3,776 = ¥9,600
```

M5Stack (CoreS3) の購入価格が全部（送料+税込み）で ¥9,220 だったので、それとだいたい同じぐらいですね。

ただし、純粋な部品コストで見ると工具（¥3,776）は除外できて、ジャンパー線も結構余分に買っているので、組み立て製品と単純に比較できるものでもないかもしれません。

> _ちなみに、マルツオンラインとAliexpressでは、本記事で利用する部品や工具以外にも色々と余分な買い物をしているので、実際の支払いは国内分 ¥8,829 + 中国分  ¥4,737 で ¥13,566 でした（マルツやAliexpressは萌えの街になる前の秋葉原でお買い物しているようでなかなか楽しいです。ついつい明らかに使わなそうな部品まで買ってしまうｗ）_

# 2. 組み立て

## 2-1. ブレッドボードの基礎

以下、ブレッドボードの電流が流れる範囲にマーク（紫）をした図を示します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2161417/8c5d3d65-9457-24f6-95aa-17cb1c390732.png)

つまり、

- `A〜E` と `F〜J` が横方向に電流が流れる
- `E` と `F` の間（くぼみ）は電流が流れない
- `+` と `-` は縦方向に電流が流れる

という仕様のようです。

## 2-2. M5StampS3 の設置

M5StampS3 は、左側のピンと右側のピンで電流を干渉させないように、絶縁列（E,F）を間に挟んだ状態で設置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2161417/b39dc449-4ae8-774b-5e1c-bc2a12ed026f.png)
なお、上図のシール上には左側から 1, 2, 3, 4, 5, 6... という順序でポートが記載されてますが、ブレッドボードに挿して利用する場合　2.54mm ピッチのコネクタを利用する必要があって、その場合は全てのポートを利用できる訳ではないようです。

:::note warn
上図では、シールを貼り付けた状態にしてしまってますが、シールは後々の工程（はんだ付け）で一度剥がす必要があるため、この時点では貼り付けない方が良いです。ただ、その状態だとどこにどのポートがあるのか分かりにくいので、シールを台紙ごとハサミで切り取り、貼り付けずに載せておくのがベターです。（なお、技適マークはシールにしか印字されてないので、シールを捨ててはいけません）
:::

### 利用可能なポート一覧

今回利用するブレッドボード（2.54mm ピッチのコネクタ用）で使用可能なポートの一覧を下表に示します。

|ブレッドボード行番号|左側ポート|右側ポート|
|:-:|:-:|:-:|
|55|`1`|n/a|
|56|`3`|n/a|
|57|`5`|n/a|
|58|`7`|`3V3`|
|59|`9`|`43 TXD`|
|60|`GND`|`44 RXD`|
|61|`5V`|`EN`|
|62|`13 SDA`|`0`|
|63|`15 SCL`|`GND`|

こちらのサイトでもわかりやすく解説されていました。

https://logikara.blog/stamps3-init/#mokuji_4-2

### GPIO

数字のポートは GPIO（General-purpose input/output）と呼ばれるもので、プログラムからその他デバイスへの入出力はこのポートを介して行います。

### SDA/SCL (I2C)

`13 SDA` と `15 SCL` は I2C というインタフェースの機器との通信で用いるものです。I2C 通信を行うデバイスと接続する時は、原則的にはこのポートを利用する必要がありそうです。（参考: [I2C通信の使い方](http://www.picfun.com/c15.html)）

### TXD/RXD (UART)

`43 TXD` と `44 RXD` は UART 通信を行うために用いるもののようです。（参考: [UARTの基本](https://www.ele-lab.com/mcu11.php)）

### Reset Signal (EN)

`EN` はリセット信号を送信するピンらしいです。

`EN` を接続機器の RESET ポート接続すれば、本体リセットした時その機器にリセット信号が飛ぶものと思われます。

なお、プログラムから LCD のリセット制御をしたい場合 EN ではなく任意の GPIO を使うこともできるようですが、そのために数に限りがある GPIO を消費するのは勿体ないので、通常は `EN` を `RESET` に繋げるのが良さそうです。

### `5V` & `3V3`

電源の給電は、M5StampS3 の USB-C ポートから行いますが、そこで得られた電力を出力するためのポートです。

このポートを外部デバイスの給電ポート（VCCなど）に接続することで、外部デバイスへの電力供給をおこなうことができます。

- `5V` は 5 ボルト
- `3V3` は 3.3 ボルト

接続する外部デバイスが何ボルトの電力を必要とするか調べて、正しいヤツを繋いであげる必要がありそうです。（最近のものは大抵 3.3 ボルトのようです）

### `GND`

グランドです。

https://www.seikatsu110.jp/library/electrical/et_short_circuit/22553/

給電を必要とするデバイスは、給電（`5V` or `3V3`）と `GND` をセットで接続する必要があります。

## 2-3. LCD の設置

まずは LCD の裏面（基板）の内容を観察してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2161417/adc56657-f211-c07f-9e0f-60ce862b368a.png)

_どうやら、左側の各PINの意味を調べる必要がありそうですね...（たくさんあって面倒くさそう）_

色々と探したところ、[コチラのデータシート](https://akizukidenshi.com/download/ds/kuongshun/msp2807.pdf)のピン配列が同じだったので、この内容を和訳しつつ、現時点で判明している M5Stack の接続先ポート（対応ポート）を下表に示します。

|PIN|意味|M5StampS3接続先|
|:-|:-|:-|
|`VCC`|電源入力|`3V3`|
|`GND`|グランド|`GND`|
|`CS`|LOW で LCD チップ選択を有効化||
|`RESET`|LOW で LCD をリセット|`EN`|
|`DC`|LCD レジスタ (HIGH) か データ (LOW) の選択信号|
|`SDI (MOSI)`|SPI バスデータ書き込み信号|`13 SDA`|
|`SCK`|SPI バスクロック信号|`15 SCL`|
|`LED`|バックライトの ON (HIGH)、OFF (LOW)|
|`SDO (MISO)`|SPI バスデータ読み込み信号<br>※読み取り不要なら配線不要|-|

> [Aliexpress の商品説明](https://ja.aliexpress.com/item/1005003005413104.html)のところに書いてありました ^^;
>> ピンの説明:
>> シリアル番号ラベルピンの説明
>> 1 vcc電源入力 (3.3v〜5v)
>> 2 GND電源グラウンド
>> 3 cs液晶フィルムセレクション
>> 4 液晶リセット
>> 5 dc液晶バスコマンド/データ選択
>> 6 sdi (mosi) lcd spiディスプレイバスデータ入力
>> 7 sck lcd spiディスプレイバスクロック信号
>> 8 LED LCDバックライトコントロール (高レベル照明)
>> 9 sdo (miso) lcd spiディスプレイバスデータ入出力。
>> 10 t_clk タッチパネルのspiバスクロック信号
>> 11 t_cs タッチパネル用spiバスのチップ選択
>> 12 t_din タッチパネルspiバスデータ入力
>> 13 t_do タッチパネルspiバスデータ出力
>> 14 t_irq タッチパネルはirq信号を中断します。

上記の表で空欄にしている `CS` `DS` `LED` は、M5StampS3 の適当な GPIO と接続して、ソフトウェアで接続した GPIO の番号（`GPIO_NUM_XX`）を指定して `HIGH` or `LOW` を書き込めば良さそうです。

また、今回ディスプレイ制御に利用する [Adafruit ILI9341](https://github.com/adafruit/Adafruit_ILI9341)のサンプル実装を幾つか見た限り、リセット信号についても GPIO 経由で送っているものが多かったので `EN` ではなく別の GPIO に接続してみても良さそうです。

> なお、以下はタッチスクリーンの信号線なので、タッチが不要な場合は配線しなくても良いようです。（今回まだタッチ機能は使用しないので配線しません）
>
> |PIN|意味|
> |:-|:-|
> |T_CS|ILI9341をSPIの通信相手として選択するときLOWとする|
> |T_DIN|SPI Master Out Slave In|
> |T_DO|SPI Master In Slave Out|
> |T_IRQ|タッチ検出したとき LOW|

## 2-4. LCD と M5StampS3 の配線

ここまでの調査で、LCD の各ピンを M5StackS3 のどのポートに接続すべきか何となく理解できたので、以下のように配線することにしました。

|LCD側PIN|M5StampS3側ポート|用途|
|:-:|:-:|:-|
|`VCC`|`3V3`|電源給電|
|`GND`|`GND`|グランド|
|`CS`|`1` (GPIO)|LCD チップ選択有効化の信号|
|`RESET`|`5` (GPIO)|リセット信号|
|`DC`|`3` (GPIO)|データ/レジスタ選択の信号|
|`SDI (MOSI)`|`13 SDA`|I2C (Stamp→LCD方向のデータ送信)|
|`SCK`|`15 SCL`|I2C (クロック同期)|
|`LED`|`7` (GPIO)|バックライト|
|`SDO (MISO)`|配線なし|LCD→Stamp方向のデータ送信は不要なため|
|`T_CS`|配線なし|今回はタッチ不要のため|
|`T_DIN`|配線なし|今回はタッチ不要のため|
|`T_DO`|配線なし|今回はタッチ不要のため|
|`T_IRQ`|配線なし|今回はタッチ不要のため|

配線は、ジャンパー線（♂♀）の♀側をLCDのPINに挿入、♂側をStamp（ブレッドボード）の穴に挿入する形で行いました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2161417/9a0675f1-831d-408f-2c63-7233dc28ec14.png)

## 2-5. 通電テスト

USBケーブルを接続して通電テストをしてみます。

なお、この段階では、ファームウェアを変更せずにテストするため、`LED` を `3V3` に接続しました。（そうしないと給電してもディスプレイが点灯しない為）

> バックライトをOFFにしなければいけないケースはあまり考えられないので、そもそも `LED` は `3V3` に接続してしまった方が良いかも？（実際、そういう配線を行っている例が幾つかありました）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2161417/2f197258-4d12-90bf-0bea-43f298aef4e0.png)

上図のようにディスプレイが点灯すれば、（少なくとも電源系の）配線は問題無さそうです。

一点気をつけた方が良いのは、M5StampS3 に取り付けるピンですが、短い方が M5StampS3 側、長い方をブレッドボード側になるように取り付けて、ブレッドボードに「ブスリ」と深くジョイントしてあげる必要があるようです。（そうしないと通電が安定しなかった）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2161417/dc1dfe10-c790-f0aa-0485-0934d4a57233.png)

# 3. LCD制御プログラム作成

以下のドライバプログラムを用いて、LCDの表示制御プログラムを記述してみます。

https://github.com/adafruit/Adafruit_ILI9341

簡単なプログラムなので Arduino IDE で書いても良かったのですが、依存ライブラリの追加などに GUI 操作が必要なのが微妙なので Platform IO で作成しました。

https://github.com/suzukiplan/m5stamps3-lcd-example

```platformio.ini
[env:m5stamps3]
platform = espressif32
framework = arduino
board = esp32-s3-devkitc-1
board_build.mcu = esp32s3
lib_deps = adafruit/Adafruit GFX Library@^1.11.7, adafruit/Adafruit ILI9341@^1.5.12
```

```src/app.cpp
#include <Adafruit_ILI9341.h>

#define PIN_CS GPIO_NUM_1
#define PIN_DC GPIO_NUM_3
#define PIN_RST GPIO_NUM_5
#define PIN_LED GPIO_NUM_7
#define PIN_MOSI GPIO_NUM_13
#define PIN_SCLK GPIO_NUM_15

static Adafruit_ILI9341 lcd(PIN_CS, PIN_DC, PIN_MOSI, PIN_SCLK, PIN_RST);

void setup()
{
    pinMode(PIN_LED, OUTPUT);
    digitalWrite(PIN_LED, HIGH);
    lcd.begin();
    lcd.startWrite();
    lcd.setRotation(2);
    lcd.writeFillRect(0, 0, lcd.width(), lcd.height(), 0x0007);
    const char* hello = "Hello, World!";
    int16_t x, y;
    uint16_t w, h;
    lcd.setTextSize(3);
    lcd.setTextColor(0xFFFF, 0x0000);
    lcd.getTextBounds(hello, 0, 0, &x, &y, &w, &h);
    lcd.setCursor(lcd.width() / 2 - w / 2, lcd.height() / 2 - h / 2);
    lcd.print(hello);
    lcd.endWrite();
}

void loop() { }
```

このファームウェアを書き込むことで、正常に Hello World が表示されれば良いのですが、私の環境では __安定的には__ 表示されませんでした。

全く表示されない訳ではないです。

何度か試していると（かなり稀にですが）表示されることもあったので、どうやらハードウェア的な問題で電流の流れが安定していないようです。

詳しい方に伺ったところ、M5StampS3とピンヘッダーのハンダ付けをしないと電流が安定しないとのことでした。

# 4. ピンヘッダーのハンダ付け

まず、M5StampS3 のシールを剥がし（※）、付属の六角レンチで基板の蓋を開けます。

:::note warn
付属のシールは技適マークがついている（本体にはついていない）ので捨ててはいけません（大事なことなのでｒｙ）
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2161417/a1935164-5b6e-0ddf-a69a-7bc2649614f6.png)

1.27mmピッチのかなり細かいスルーホールなので、ハンダ付けの難度が少し高そうです。

一般的なスルーホール（2.54mmピッチ）の穴と比べてみると分かりやすいです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2161417/07666895-9c07-5200-fc62-090a96caf248.png)

ハンダ付けしないと使い物にならないレベルで電流が安定しないのであれば、最初から2.54mmピッチのスルーホールにして欲しかった感があります。仮にポート数を減らして2.54mmピッチにしたM5StampS3が登場したら、間違いなくそちらの方がオススメです。

> _M5Stamp Pico というものがありましてな...（Raberry Pi Picoでも良いかもしれない）_

はんだ付けのやり方は以下の動画を参考にしました。

https://www.youtube.com/watch?v=xz3dy3qTXCI

こんな手際よくできる訳ないだろJK

...などと思いつつ人生初のはんだ付けをしたらこんな感じになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2161417/ea40afe1-ba67-9833-cf2a-e5ff1ee5e7c8.png)
うむ...汚いですね^^;

何やら、関係ない穴に落としていたり、ムラだらけなのでやや心配になりますが、概ねショートしてなさそうな感じなので、**多分** 大丈夫そうな気がします。

まぁ、失敗していてもはんだ吸収線を保険で買ってあるので問題ないでしょう。

という訳で、とりあえずこの状態で通電してみたところ、無事安定的に Hello, World! （冒頭の写真）が表示されるようになりました。

# 編集後記

画面クリア（`Adafruit_ILI9341::writeFillRect`）やテキスト表示（`Adafruit_ILI9341::print`）のレスポンスが想定より遅い点がやや気になります。

> 「[1-4. LCD](#1-4-lcd)」でも記載してますが、ILI9342C だとまた結果が違ってくるかも？

この点は M5GFX（LovyanGFX） を使うことで解消できそうな気がしますが、I2C (SCLK, MOSI) や CS/DC の GPIO ポート番号が M5Stack とは異なる状態なので、M5Stack 向けのライブラリを使うにはひと手間必要だと思われます。

`Adafruit_ILI9341` なら任意の I2C (SCLK, MOSI) と CS/DS が指定できお手軽に対応できそうだったので今回使ってみた形です。

次はディスプレイドライバのM5GFX（またはLovyanGFX）化を試したいところです。

M5GFX（またはLovyanGFX）に対応できれば、晴れてM5Stackの代替開発環境として使えそうです。つまり、まだM5Stackのデバッグ環境としては使い物にはならない状態です。

> _ついでに、私の用途の都合でDACモジュールや入力装置（ゲームパッド）も取り付けたいところ...（何やら、自作ゲーム機とかも作れそうな気がしてきた）_

# 追記

## 2023.07.28

`Adafruit_ILI9341` → `LovyanGFX` に変更したら実用的な速度が出るようになる

https://qiita.com/suzukiplan/items/e7f66d1b8ae7d6c7e03e

## 2023.07.29

MSX1 エミュレータを動かすことに成功

https://qiita.com/suzukiplan/items/84d2d5fcdf3fc303a124

## 2023.07.29

DAC モジュール (UDA1334A) を用いて音声の再生に対応

https://qiita.com/suzukiplan/items/8724bbda1684a04c8884