M5Stackメモ

これは、自分用メモです。(随時更新)

#注意
ケーブル(Type-C)の表裏があることがある。
長いケーブルはうまく認識できないことがある。

#ハード
##Bus
|GPIO||M5Stack Basic|PULL<br/>UP|備考|M5Port Explain|ESP32 ADC/DAC|M5Fire| 
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|G23|MOSI|TF_DI<br/>ILI9342C_MOSI_MISO|12K||||-|
|G19|MISO|TF_DO|12K||||-|
|G18|SCK|TF_SCLK<br/>ILI9342C_CLK|12K||||-|
|G3 |IO0<br/>RXD1|USB_RXD0|||||-|
|G16|IO2<br/>RXD2||||Port C<br/>(Blue)<br/>UART||GROVE-C<br/>PS-RAM|
|G21|IO4<br/>SDA|GROVEA_SDA<br/>IP5306|||Port A<br/>(Red)<br/>I2C||MPU6886_SDA<br/>BMM150_SDA|
|G2|IO6|||WiFi使用時にADC使えない<br/>起動時のモード選択で利用される||ADC2|||
|G12|IO8<br/>IIS_SCLK|-||起動時に1だと LDOが1.8V,<br/> 0だと3.3Vになる*<br/>WiFi使用時にADC使えない||ADC2|-|
|G15|IO10<br/>IIS_OUT|-||標準でPULLUP 起動時に設定すると SDIOスレーブタイミングの設定*<br/>WiFi使用時にADC使えない||ADC2|LED_BAR|
|G35|ADC1|||入力専用?*||ADC1|||
|G36|ADC2|||入力専用?*|Port B<br/>(Black)<br/>ADC|ADC1|GROVE-B|
|G25|DAC0<br/>AUDIO_L<br/>Speaker|Speaker||||DAC1|-|
|G26|DAC1<br/>AUDIO_R|||WiFi使用時にADC使えない|Port B<br/>(Black)<br/>DAC|DAC2|GROVE-B|
|G1|IO1<br/>TXD1|USB_TXD0|||||-|
|G17|IO3<br/>TXD2||||Port C<br/>(Blue)<br/>UART||GROVE-C<br/>PS-RAM|
|G22|IO5<br/>SCL|GOVEA_SCL<br/>IP5306_SCL|||Port A<br/>(Red)<br/>I2C||MPU6886_SCL<br/>BMM150_SCL|
|G05|IO7|-||標準でPULLUP 起動時に設定すると SDIOスレーブタイミングの設定*|||-|
|G13|IO9<br/>IIS_WS|||||ADC2||
|G0|IO11<br/>IIS_MCLR<br/>BOOT|AUTO_DOWNLOAD|12K|使用不可<br/>起動時のモード選択で利用される||ADC2|-|
|G34|ADC0<br/>IIS_IN|||入力専用?*||ADC1|MIC|
|||||||||||
|G39||BTN A||入力専用?*||ADC1|-|
|G38||BTN B||入力専用?*||ADC1|-|
|G37||BTN C||入力専用?*||ADC1|-|
|||||||||||
|G4||TF_CS|12K|WiFi使用時にADC使えない||ADC2|-|
|G33||ILI9342C_RST||||ADC1|-|
|G27||ILI9342C_DC||WiFi使用時にADC使えない||ADC2|-|
|G14||ILI9342C_CS||WiFi使用時にADC使えない||ADC2|-|
|G32||ILI9342C_BL|100k<br/>PullDown|||ADC1|-|

ドキュメント　https://docs.m5stack.com/#/en/core/basic
図面　https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/schematic/Core/M5-Core-Schematic(20171206).pdf
* http://ghz2000.com/wordpress/?p=1418
入力専用は、チップ内のPullUPができないみたい
**【ESP32】Wifi接続時のanalogReadについて　https://rikoubou.hatenablog.com/entry/2017/07/26/193021

GPIO12 Easter Eggに割り当て？　https://macsbug.wordpress.com/2017/01/04/easter-egg-of-esp-32/
##M5Stack　Fire
###Grove端子CはPSRAMと兼用不可。
使いたい場合はArduinoIDEのツールのPSRAMをDisableにする。

##M5StickC
FTDIのUSB-Serial変換器らしい。（M5Stackとは違う）
USBドライバーがないときは、下記から持ってくる。真ん中あたりの表の右（WHQL Certified. Includes VCP and D2XX.
Available as a setup executable が便利)
https://ftdichip.com/drivers/vcp-drivers/

##M5StickC Plus
HATの出力ポート

```
 pinMode(25, OUTPUT);
  gpio_pulldown_dis(GPIO_NUM_36);
  gpio_pullup_dis(GPIO_NUM_36);
```

HATの方のWireはWire1を利用する。スピードを指定する必要あり？

```
Wire1.begin(0, 26);
Wire1.setClock(50000);
```

##base15
M5Stack Basic　と　Base15　の組み合わせが便利(電池不要・固定）
https://m5stack.com/collections/m5-base/products/base15-proto-industrial-board-module
Groveコネクタは配線してないので自由に結線できます。（代わりに電源も結線が必要）
ACアダプタは９−２４Vが使用可能　https://www.switch-science.com/catalog/1795/
DC／DCコンバータ　https://www.tij.co.jp/jp/lit/ds/symlink/tps54360.pdf
RS485のボードがなぜかついているが端子がない。（別途購入すれば使える？・Base26と同じパッケージ？）
DINもしくはひっかけネジで固定できそう。
DINの固定はネジ1本？
DIN使用時はM5Stackが横向きになるので注意(コードが下向きの方が良いからそれはそう）
  ```M5.lcd.setRotation(2);``` で横向きにする。
 
付属の六角レンチはなめやすいので、市販品を使った方が良さそう

##Pb.HUB
https://docs.m5stack.com/#/en/unit/pbhub
IOが5Vなので、SeeedStudioの5V　Digitalの物がつかえそう
https://wiki.seeedstudio.com/Grove-2-Channel_SPDT_Relay/(例えば
スケッチ例のm5Stack　unit pbhub　のヘッダーファイルとライブラリをコピーして使う
多分ライブラリはNeopixelが接続して簡単に使えるように書いてある。未確認
ドキュメントの図面ではGROVE1個あたりにINとOUTが一個ずつだったが、デジタルは入出力2本ずつで利用可能、アナログ入力は1本だけ
5A,6Aはデジタル入力のみ、出力不可
5B,6Bはデジタル出力のみ、入力不可

#Firmware(M5Burner)
注意：勘です。
なんかnode.jsで動いているみたい。(bin\Resources\app.asarを展開するとソースが見れる。）
##Proxyでデータ(binファイルが持ってこれないとき)
一覧は環境変数のHTTP_PROXYとHTTPS_PROXYを設定し、M5Burnerを起動すれば持ってきます。
肝心のbinファイルは、下図の”A",”B",”C"がわかれば、http://firmware-cdn.m5stack.com/firmware/A-B(小文字で)-C.bin で取得できるみたい。この場合だとhttp://firmware-cdn.m5stack.com/firmware/UIFlow_StickC-stickc-v1.7.3.bin になります。
取得したファイルをA-C.binにリネーム（この場合はUIFlow_StickC-v1.7.3.bin）して\packeages\fw\Bのフォルダ(この場合は\packeages\fw\stickc)に入れる。
M5Burnerを立ち上げるとBurnできるようになっていると思う。
※Bは、たぶん正式には　\packages\fw\local.json をみるとわかる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/97061/17392a8a-bf84-8f38-0254-7408b52fa7b2.png)




#ソフト（Arduino)
##注意すること。
3秒以内に1回はdelay(1)をいれWDTをリセットすること。https://www.mgo-tec.com/blog-entry-arduino-esp32-multi-task-dual-core-01.html/3
##比較
| BASIC | Stick | Stick C Plus | 備考 |
|:--|:--|:--|:-:|
|M5.Speaker.begin();<br/>M5.Speaker.mute(); |---|M5.Beep.begin();<br/>M5.Beep.mute();|スピーカから音がするときの対処|
|M5.Lcd.setBrightness(0-255);|M5.Axp.begin();<br/>M5.Axp.ScreenBreath(7-15);|M5.Axp.begin();<br/>M5.Axp.ScreenBreath(7-15);|液晶バックLEDの明るさ|
|M5.Power.reset();|esp_restart();|esp_restart();|リセット|

##API

```
System:
        M5.begin();
        M5.update();
    Power:
        M5.Power.setPowerBoostKeepOn()
        M5.Power.setCharge(uint8_t mode);
        M5.Power.setPowerBoostKeepOn(bool en);
        M5.Power.isChargeFull();
        M5.Power.setWakeupButton(uint8_t button);
        M5.Power.powerOFF();
        bool setPowerBoostOnOff(bool en);
        bool setPowerBoostSet(bool en);
        bool setPowerVin(bool en);
        bool setPowerWLEDSet(bool en);
    LCD:
        M5.lcd.setBrightness(uint8_t brightness);
        M5.Lcd.drawPixel(int16_t x, int16_t y, uint16_t color);
        M5.Lcd.drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color);
        M5.Lcd.fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
        M5.Lcd.fillScreen(uint16_t color);
        M5.Lcd.drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color);
        M5.Lcd.drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername,uint16_t color);
        M5.Lcd.fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color);
        M5.Lcd.fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername,int16_t delta, uint16_t color);
        M5.Lcd.drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color);
        M5.Lcd.fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color);
        M5.Lcd.drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color);
        M5.Lcd.fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color);
        M5.Lcd.drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color);
        M5.Lcd.drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[], int16_t w, int16_t h),
        M5.Lcd.drawChar(uint16_t x, uint16_t y, char c, uint16_t color, uint16_t bg, uint8_t size);
        M5.Lcd.setCursor(uint16_t x0, uint16_t y0);
        M5.Lcd.setTextColor(uint16_t color);
        M5.Lcd.setTextColor(uint16_t color, uint16_t backgroundcolor);
        M5.Lcd.setTextSize(uint8_t size);
        M5.Lcd.setTextWrap(boolean w);
        M5.Lcd.printf();
        M5.Lcd.print();
        M5.Lcd.println();
        M5.Lcd.drawCentreString(const char *string, int dX, int poY, int font);
        M5.Lcd.drawRightString(const char *string, int dX, int poY, int font);
        M5.Lcd.drawJpg(const uint8_t *jpg_data, size_t jpg_len, uint16_t x, uint16_t y);
        M5.Lcd.drawJpgFile(fs::FS &fs, const char *path, uint16_t x, uint16_t y);
        M5.Lcd.drawBmpFile(fs::FS &fs, const char *path, uint16_t x, uint16_t y);
    Button:
        M5.BtnA/B/C.read();
        M5.BtnA/B/C.isPressed();
        M5.BtnA/B/C.isReleased();
        M5.BtnA/B/C.wasPressed();
        M5.BtnA/B/C.wasReleased();
        M5.BtnA/B/C.wasreleasedFor()
        M5.BtnA/B/C.pressedFor(uint32_t ms);
        M5.BtnA/B/C.releasedFor(uint32_t ms);
        M5.BtnA/B/C.lastChange();
    Speaker:
        M5.Speaker.tone(uint32_t freq);
        M5.Speaker.tone(freq, time);
        M5.Speaker.beep();
        M5.Speaker.setBeep(uint16_t frequency, uint16_t duration);
        M5.Speaker.mute();
```
M5.Lcd.drawxbitmapやdrawString,drawFloatなども使えるが、ここでは書いてないなあ

   


###M5.beginの定義、中身
```
void M5Stack::begin(bool LCDEnable, bool SDEnable, bool SerialEnable, bool I2CEnable) {
  // Correct init once
  if (isInited == true) {
    return;
  } else {
    isInited = true;
  }

  // UART
  if (SerialEnable == true) {
    Serial.begin(115200);
    Serial.flush();
    delay(50);
    Serial.print("M5Stack initializing...");
  }

  // LCD INIT
  if (LCDEnable == true) {
    Lcd.begin();
  }

  // TF Card
  if (SDEnable == true) {
    SD.begin(TFCARD_CS_PIN, SPI, 40000000);
  }

  // TONE
  // Speaker.begin();

  // Set wakeup button
  Power.setWakeupButton(BUTTON_A_PIN);

  // I2C init
  if (I2CEnable == true) {
    Wire.begin(21, 22);
  }

  if (SerialEnable == true) {
    Serial.println("OK");
  }
}
```
###M5.updateの中身
```
void M5Stack::update() {
  //Button update
  BtnA.read();
  BtnB.read();
  BtnC.read();

  //Speaker update
  Speaker.update();
}
```
###新しいボタンの定義(Dual ButtonをGroveのB端子につないだ時）
```
Button BtnRed = Button(G26, true, 10);
Button BtnBlue = Button(G36, true, 10);
```
pinMode(_pin, INPUT_PULLUP);になっているので、回路はGNDに接続するだけでOK。ただし入力専用のポートはPullUPできないのでPullUP抵抗が必要
https://github.com/m5stack/M5Stack/blob/master/src/utility/Button.cpp
ただし、この場合が、m5.updateで更新されないので、個別に.readする必要あり。

``` 
BtnRed.read();
BtnBlue.read();
```
   
##FONTの定義(m5stack.h)
```
#define LOAD_GLCD   // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
#define LOAD_FONT2  // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
#define LOAD_FONT4  // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
#define LOAD_FONT6  // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
#define LOAD_FONT7  // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-.
#define LOAD_FONT8  // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT
#define LOAD_GFXFF  // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
```
##色の定義(In.eSPI.h)
```
// New color definitions use for all my libraries
#define TFT_BLACK       0x0000      /*   0,   0,   0 */
#define TFT_NAVY        0x000F      /*   0,   0, 128 */
#define TFT_DARKGREEN   0x03E0      /*   0, 128,   0 */
#define TFT_DARKCYAN    0x03EF      /*   0, 128, 128 */
#define TFT_MAROON      0x7800      /* 128,   0,   0 */
#define TFT_PURPLE      0x780F      /* 128,   0, 128 */
#define TFT_OLIVE       0x7BE0      /* 128, 128,   0 */
#define TFT_LIGHTGREY   0xC618      /* 192, 192, 192 */
#define TFT_DARKGREY    0x7BEF      /* 128, 128, 128 */
#define TFT_BLUE        0x001F      /*   0,   0, 255 */
#define TFT_GREEN       0x07E0      /*   0, 255,   0 */
#define TFT_CYAN        0x07FF      /*   0, 255, 255 */
#define TFT_RED         0xF800      /* 255,   0,   0 */
#define TFT_MAGENTA     0xF81F      /* 255,   0, 255 */
#define TFT_YELLOW      0xFFE0      /* 255, 255,   0 */
#define TFT_WHITE       0xFFFF      /* 255, 255, 255 */
#define TFT_ORANGE      0xFDA0      /* 255, 180,   0 */
#define TFT_GREENYELLOW 0xB7E0      /* 180, 255,   0 */
#define TFT_PINK        0xFC9F
```

##画面設計
![M5Stack寸法.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/97061/a53f8cc2-c22b-ccec-8555-faa1210bca9b.png)

なるべく部品ごとに絵をかいてスプライトで表示した方が良さそう。
###XBITMAP
https://en.wikipedia.org/wiki/X_BitMap
####XBITMAPを使うと便利。
fontにない日本語とかをイメージで表示
SDカードとか不要
黒が背景になる。
白は書くときに指定した色になる。(スプライト表示時に色が指定できる）
####使い方
イラレ(RGB) -PNG-> 変換サイト -XBM->書き換え-->ヘッダーファイル
変換サイト　https://www.online-utility.org/image/convert/to/XBM
書き換えは、ファイルをコピーして、ファイルの内容の先頭を以下のように変更し拡張子をXBMからhに変更。ファイルをスケッチと同じフォルダに置いてArduinoIDEでスケッチを読み込むと羅列される。定義名はファイル名と一緒が分かりやすい。

```
#define 1594346505063_width 50
#define 1594346505063_height 50
static char 1594346505063_bits[] = {
```

↓

```
#include <Arduino.h> 

#define btn1_width 50
#define btn1_height 50
PROGMEM const unsigned char btn1_bits[] = {
```
あとは、スケッチでinclude```#include"btn1.h"```で読み込み、描画関数```M5.lcd.drawXBitmap(0, 0, btn1_bits, btn1_width, btn1_height, TFT_WHITE);```と書くだけです。

####変化する文字・数値
7Seg風に書く```drawFloat(omosa, 2, 300, 20, 7);```
スプライトを使った方が画面の変化がなめらか。
例

```
TFT_eSprite spr = TFT_eSprite(&M5.Lcd);
void setup() {
  spr.setColorDepth(8);
  spr.createSprite(320, 145);
}
void loop(){
  spr.fillRect(0, 0, 320, 145, TFT_BLACK);
  spr.setTextSize(2);
  spr.setTextDatum(TR_DATUM);
  spr.setTextColor(TFT_WHITE, TFT_BLACK);
  spr.drawFloat(omosa, 2, 300, 20, 7);
  spr.pushSprite(0, 20);
}
```

##M5Stack　Avator
Timer内の変数はうまく表示できない。下の```char s[10];```の位置に着目
ダメな例

```
#include <M5Stack.h>
#include <Avatar.h>
#include<Ticker.h>
using namespace m5avatar;

Avatar avatar;
Ticker Timer;

void TimeTick() {
  static int i = 100;
  char s[10];
  sprintf(s, "%d ppm", i);
  avatar.setSpeechText(s);
  i++;
}

void setup() {
  M5.begin();
  Timer.attach_ms(2000, TimeTick);
  avatar.init();
}

void loop() {
  M5.update();
  delay(1);
}
```

良い例

```
#include <M5Stack.h>
#include <Avatar.h>
#include<Ticker.h>
using namespace m5avatar;

Avatar avatar;
Ticker Timer;
char s[10];

void TimeTick() {
  static int i = 100;
  sprintf(s, "%d ppm", i);
  avatar.setSpeechText(s);
  i++;
}

void setup() {
  M5.begin();
  Timer.attach_ms(2000, TimeTick);
  avatar.init();
}

void loop() {
  M5.update();
  delay(1);
}
```

#Bluetooth Serialでの接続サンプル
ArduinoIDEのシリアルモニタでは見れない時がある。TeraTermなど他のターミナルソフトも試すべき
一旦離れた時の処理を書くこと。でないと再接続できない。リセットが必要

```
#include "BluetoothSerial.h"
BluetoothSerial SerialBT;
void setup() {
  Serial.begin(9600);
//  delay(100);　//おまじない。あった方が御利益ありそう。
  Serial.println("**Start*");
  SerialBT.begin("ESP32test");
  Serial.println("BTReady");
}

void loop() {
  static int i = 1;
  static bool isConnected = false;
  if (!SerialBT.connected(100)) {
        Serial.println("BT disconnect");
    if (isConnected) {
      SerialBT.disconnect();
      isConnected = false;
    }
  } else {
    Serial.println("BT Connected");
    isConnected = true;
  }
  
  SerialBT.print(i);
  SerialBT.println(":hello World!");
  i++;
  delay(1000);
}
```