M5Stack Basic/Gray を他のマイコンやRaspberry Piの UART モニターとして使う

M5Stack と 他のマイコン間をシリアル(UART)でつなげて双方向通信ができるようにしました。

以下は Wio LTE JP Version (以下 Wio LTE) と M5Stack Gray (以下 M5Stack) をつなげた様子です。`<<Send>>: ` で送られたデータが別のウィンドウ側で `Recv: ` として受信できています。
(クリックすると大きい画像で見られます)
[![a.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22754/cdb5c73c-7635-ee52-0003-476b46be387d.gif)](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22754/cdb5c73c-7635-ee52-0003-476b46be387d.gif)

3.3V な UART デバイスであれば通信できるので、Wio LTE だけでなく Raspberry Pi 等の UART ターミナルデバイスとして M5Stack が利用可能となります。

※ここでは Gray か Basic を想定しています。FIRE や Go で同様のことができるのかは、未調査です。

## M5Stack の Grove A ポートで SoftwareSerial を使う

M5Stack には側面に 1 つ Grove コネクタ (["Grove A" と呼ばれている](https://github.com/m5stack/M5Stack#4-hw-reference)ようです) があるので、そこにケーブルを挿すだけで他のマイコンと通信できるようにしたというのがゴールです。

**ちなみに:** M5Stack には HardwareSerial があり、[GPIO 16,17 で Serial2](https://github.com/m5stack/M5Stack/blob/master/examples/Advanced/Serial2/Serial2.ino#L11) として使うことができますが、これは M5-BUS にピンなどを挿して利用することになるため、ちょっとダサいなあと思っています。

### Grove A のピンアサイン

Grove A は GPIO 21 と 22 に割り当たっていて I2C として使えるようにもなっていますが、 DIO としても利用可能ですので SoftwareSerial としても使えます。

### EspSoftwareSerial

[EspSoftwareSerial](https://www.arduinolibraries.info/libraries/esp-software-serial) は arduino-esp32 プラットフォームで SoftwareSerial が使えるようにするライブラリです。

[スケッチ] > [ライブラリをインクルード] > [ライブラリを管理] から `EspSoftwareSerial` を探してインストールできます。

基本のコードは以下の通りです。

```c++
#include <M5Stack.h>
#include <SoftwareSerial.h>
SoftwareSerial GroveA(21, 22);

setup () {
  M5.begin();
  GroveA.begin(57600);
}
```

あとは `GroveA` で `write` や `read` などのメソッドを使ったシリアルポートプログラミングをしていきます。

### サンプルスケッチ

5秒毎に `millis()` を UART から送出しつつ、その間に UART で受信したデータを LCD と M5Stack のシリアルモニタ(ややこしいな)へ表示するスケッチです。

※ M5Stack のシリアルモニタは `define` で `CONSOLE` と名称定義しています(ややこしいから)

```c++:m5stack_softwareserial.ino
#include <M5Stack.h>
#define CONSOLE Serial

#include <SoftwareSerial.h> /* EspSoftwareSerial */
/*                 rxPin, txPin | https://github.com/plerup/espsoftwareserial/blob/master/src/SoftwareSerial.h#L93 */
SoftwareSerial GroveA(21, 22);

void setup() {
  M5.begin();
  M5.Lcd.setTextSize(2);
  M5.Lcd.setTextColor(M5.Lcd.color565(255, 255, 255));
  CONSOLE.begin(57600); /* ref: https://qiita.com/inouetai/items/a4f8b134be7cc40bc42e */
  GroveA.begin(57600); /* ref: https://github.com/plerup/espsoftwareserial/blob/master/src/SoftwareSerial.h#L118 */
  delay(5000);
  CONSOLE.println("-- HELLO (baud rate = 57600)");
}

void loop() {
  M5.Lcd.fillScreen(M5.Lcd.color565(0, 0, 0));
  M5.Lcd.setCursor(0, 0);
  while (GroveA.available()) {
    String recv_str = GroveA.readStringUntil('\n');
    CONSOLE.print("Recv: ");
    CONSOLE.println(recv_str);
    M5.Lcd.print("Recv: ");
    M5.Lcd.println(recv_str);
  }
  
  unsigned long uptime_ms = millis();
  GroveA.println(uptime_ms);
  CONSOLE.print("<<Send>>: ");
  CONSOLE.println(uptime_ms);
  
  delay(5000);
}
```

### 注意点

#### SoftwareSerial の通信速度は最大で 57600bps にしておくのが良さそう

通信速度は **57600 を最大としておいた方が良さそう**です。
115200 だと化けることがありました。おそらく処理が間に合わないことがあるのかもしれません。(74880 は未調査ですがわかりづらいのでパスしました)

スケッチ内では `CONSOLE` 側も同じ 57600 にしていますが、ここは `CONSOLE.begin(115200)` でも問題ありません (開発 PC と M5Stack 間の通信速度であるため)

#### M5.Power.** が使えなくなります

M5Stack の電源関連の制御は [GPIO 21,22 を通じて行われています](https://github.com/m5stack/M5Stack/blob/947d42b803790014b10b9cf248cec6a635262dce/src/utility/Power.cpp#L80)。そのため SoftwareSerial で GPIO 21,22 を占有してしまうと [`M5.Power.getBatteryLevel()`](https://github.com/m5stack/m5-docs/blob/master/docs/ja/api/power.md#getbatterylevel) などが全般的に使えなくなります。

回避方法は現状見いだせていません。

#### 入力可能な電圧レベルは 3.3V です

M5Stack が使っている ESP32 の GPIO は 3.3V です。 **[5V トレラントではない](https://trac.switch-science.com/wiki/esp32_tips#GPIO)** ので、信号出力が 3.3V 以外のデバイスと接続する際には[電圧レベル変換](http://akizukidenshi.com/catalog/g/gK-06464/)をしてください。

Wio LTE や Raspberry Pi は 3.3V ですのでそのまま接続が可能です。

## Wio LTE とつなげる

[Wio LTE JP Version での UART ポート操作](https://qiita.com/ma2shita/items/18b6e1308d4a5a80ab31#wio-lte-jp-version-%E3%81%A7%E3%81%AE-uart-%E3%83%9D%E3%83%BC%E3%83%88%E6%93%8D%E4%BD%9C) を参考にしています。

こちらは 2秒毎に `millis()` を UART から送出しつつ、その間に UART で受信したデータを Wio LTE のシリアルモニタ(ややこしいな)へ表示するスケッチです。

```c++:wiolte_hardwareserial.ino
#include <WioLTEforArduino.h>
WioLTE Wio;
#define CONSOLE SerialUSB
#define GroveUART Serial

void setup() {
  Wio.Init();
  Wio.PowerSupplyGrove(true);
  CONSOLE.begin(57600);
  GroveUART.begin(57600);
  delay(5000);
  CONSOLE.println("-- HELLO (baud rate = 57600)");
}

void loop() {
  while (GroveUART.available()) {
    String recv_str = GroveUART.readStringUntil('\n');
    CONSOLE.print("Recv: ");
    CONSOLE.println(recv_str);
  }

  unsigned long uptime_ms = millis();
  GroveUART.println(uptime_ms);
  CONSOLE.print("<<Send>>: ");
  CONSOLE.println(uptime_ms);

  delay(2000);
}
```

### M5Stack と Wio LTE を Grove ケーブルでつなげる

M5Stack の Grove A と Wio LTE の Grove UART を Grove ケーブルで接続すると、双方でデータの送受信がされるようになります。これは双方の TX と RX がクロスするように M5Stack 側のスケッチの `SoftwareSerial GroveA(21, 22);` で指定しているからです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22754/12a533af-fbda-1ca6-9b25-acc29064592e.png)

**注意点: 電源(赤) は結線しないように切断してください！**
写真の通り、赤線(電源)を切断した改造を行っています。電源をそれぞれ接続すると最悪壊れますのでご注意を。

## Raspberry Pi とつなげる

あとでかく (LGTM をもらったら気合が入るよ！)

## あとがき

今後考えられるアップデートは ...

* LCD でスクロールできるようにする (e.g. https://mae8bit.hatenablog.com/entry/2019/11/27/232308)
* M5Stack のボタンに応じてコマンドをマイコン側に送出
* [M5Stack 用 3G 拡張ボード](https://soracom.jp/products/kit/3g_module_m5stack/) を使って
    * 受信データをクラウドに送出 
    * [SORACOM Napter](https://soracom.jp/services/napter/) を使ってクラウド側から M5Stack を経由してコマンド文字列をマイコン側へ送出

こんなところでしょうか。どなたか、時間をください。

### 「お詫び」

[M5Stack用3G拡張ボードを使う際、PIN(16,17)を利用するデバイスの対応](https://qiita.com/ma2shita/items/e6f84f1d2e8c94e12e31) で

> ※ ちなみに arduino-esp32 では SoftwareSerial が利用できません

と偉そうに書いていたのですが "[ESP32でSoftwareSerial接続する](https://otomizu.work/2019/10/16/esp32-softwareserial-arduino-ide/)" に「[EspSoftwareSerial](https://www.arduinolibraries.info/libraries/esp-software-serial) が使えるよ」と書いてあるじゃないですか！
良く調べもせずに書いてスミマセンでした、謹んで反省してまーす。

EoT