Posted at

M5Stack用3G拡張ボードを使う際、PIN(16,17)を利用するデバイスの対応


どういうこと?

M5Stack用3G拡張ボード は、M5Stack本体との通信に GPIO PIN の (16, 17) をUARTで利用します。一方で、その他の拡張ボードでも通信に同じPINを使うケースがあります。例えば M5Stack 用 GPS 拡張ボードです。

これらのボードを組み合わせて利用する場合、標準の状態ではPINが競合するため利用ができませんので、これについて対応する方法を記載しています。

※ 不可逆な改造を含みますのでAt Your Own Riskでお願いしますー


M5Stack 用 3G 拡張ボード側では対応できません

M5Stack用3G拡張ボード(以下、3G 拡張ボード)にはピンアサイン(通信に使用するPIN)を変更する機能がありません。そのため、その他の拡張ボード側で対応※する必要があります。

※ その他の拡張ボード側にピンアサインを変更する機能が求められますし、ない場合は、、、残念ですが、どちらか一方を使うことになります (-人-)


M5Stack用GPS拡張ボードの場合 (ピンアサイン変更可能モジュール)

M5Stack用GPS拡張ボードはピンアサイン変更機能が存在するため、3G拡張ボードと組み合わせて利用することが可能です。

具体的にはハードウェア側、ソフトウェア側それぞれの対応を行い、(16, 17) から (13, 5) に変更します。


準備


  • カッター

  • ハンダごて、ハンダ、ハンダ吸取

  • テスター

  • 銅線など(オプション)


ハードウェア編

※ 不可逆な改造を含みますのでAt Your Own Riskでお願いしますー



  • (16, 17) の「白い線」をカッターで切断します。(正確には白い線の下に実装されている回路パターンを切り離します)


  • (13, 5) のターミナル(盛り上がってる部分)を銅線(もしくはハンダ自体)でつなげます

※ テスターを当てながら、切断ができているか、接続ができているかを確認しましょう



実際にやった様子

(16, 17) に戻す場合は、 (13, 5) を切断(ハンダ吸い取り)をし、(16, 17) を接続します。


ソフトウェア編

(13, 5) を利用する最小限のコードは以下の通りです。

 HardwareSerial M5StackGPS(1);

void setup() {
M5StackGPS.begin(9600, SERIAL_8N1, 13, 5);
}

arduino-esp32では Serial2 までが定義されていますが、(13, 5) を指定している HardwareSerial は定義されていないため、直接 (13, 5) をUART通信用ピンとして指定します。

HardwareSerial インスタンス生成時の引数 1 については、0 ~ 2 のうちの整数を指定すればOKなのですが、 0 を指定するとコンソール用のUARTと競合することがわかっているため、1 もしくは 2 を指定します。

その後、begin の引数で利用するピン指定が上書きされるため、インスタンスを生成するためだけのおまじないだと理解いただければ。

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


3G拡張ボードと組み合わせて使う例

これまでの作業で3G拡張ボードとの競合は解消されたので、同時に利用することができるようになります。

位置情報を取得し、SORACOM Harvest Data へ送信するコード (UnifiedEndpoint 利用) の例です。


m5stack_with_gps_and_3g.ino

#include <M5Stack.h>

#include <string.h>
#define CONSOLE Serial

/* Required: change the PIN assignment from 16,17 to 13,5 on the GPS module of M5Stack. */
HardwareSerial M5StackGPS(1); /* place of `1` required 1 or 2 (overrided by `#begin`) see: https://github.com/espressif/arduino-sp32/blob/master/cores/esp32/HardwareSerial.cpp#L33 */
#include <TinyGPS++.h>
TinyGPSPlus gps;

#define TINY_GSM_MODEM_UBLOX
#include <TinyGsmClient.h>
#define MODEM Serial2
/* 3G modem serial port */
TinyGsm modem(MODEM);
TinyGsmClient ctx(modem);

void modem_begin(TinyGsm &modem) {
modem.restart();
while (!modem.waitForNetwork());
modem.gprsConnect("soracom.io", "sora", "sora");
while (!modem.isNetworkConnected());
IPAddress ipaddr = modem.localIP(); CONSOLE.println(ipaddr);
}

void setup() {
M5.begin();
M5StackGPS.begin(9600, SERIAL_8N1, 13, 5);/* Setup for GPS module */
MODEM.begin(115200, SERIAL_8N1, 16, 17);/* Setup for 3G module */
}

void loop() {
/* Get from GPS */
while (M5StackGPS.available() > 0)
gps.encode(M5StackGPS.read());
if (!gps.location.isValid()) {
CONSOLE.println("gps.location is invalid");
return;
}
/* Create JSON */
char payload[1024];
sprintf(payload, "{\"lat\": %.7f, \"lng\": %.7f, \"alt\": %.1f}",
gps.location.lat(), gps.location.lng(), gps.altitude.meters());
CONSOLE.println(payload);

/* checking connect status before send */
if (!modem.isGprsConnected()) {
CONSOLE.println("reconnecting");
modem_begin(modem);
}
/* connect to host */
if (!ctx.connect("uni.soracom.io", 80)) {
Serial.println(F("Connect failed."));
return;
}
Serial.println(F("connected."));
/* send request */
ctx.println("POST / HTTP/1.0");
ctx.println("Host: uni.soracom.io");
ctx.println("Content-Type: application/json");
char content_length_hdr[32];
sprintf(content_length_hdr, "Content-Length: %lu", strlen(payload));
ctx.println(content_length_hdr);
ctx.println();
ctx.println(payload);
CONSOLE.println("sent.");
/* receive response */
while (ctx.connected()) {
String line = ctx.readStringUntil('\n');
CONSOLE.println(line);
if (line == "\r") {
CONSOLE.println("headers received.");
break;
}
}
char body[1*1024] = {0};
ctx.readBytes(body, sizeof(body)); /* body */
ctx.stop();
CONSOLE.println(body);

delay(5000);
}


参考資料

EoT