15
21

More than 3 years have passed since last update.

VSCodeとPlatformIOでM5Stack Core2開発

Last updated at Posted at 2021-03-28

いつの間にかPlatformIOでM5Core2がサポートされていた(以前は他のボード設定を流用する必要があった)ので、設定方法をまとめる。
また、次のようなサンプルコードで動作を確認する。
サンプルコード1: 画面表示とバッテリー情報読み出し
サンプルコード2: Wifi接続とNTPによるRTCへの時刻設定
サンプルコード3: GPIOとADC
サンプルコード4: マイクロSDへのデータ書き込み
動作確認はWindows 10とVSCodeを使用している。

参考資料
公式ページ(回路図等はここから)
Arduinoライブラリ(大体の使い方はM5Core2/examples/でわかる)
最初に書き込まれているFactory test image
MCUとして使用されているESP32-D0WDQ6-V3のデータシート

M5Core2用プロジェクトの作り方

PlatformIOのインストールとプロジェクト生成

VSCodeの拡張機能からPlatformIOをインストールし、VSCodeを再起動する。
Extension_ PlatformIO IDE - Visual Studio Code 2021_03_27 20_44_07.png
PIO HomeからProjects & Configurationを選択し、Create New Projectをクリック。
PIO Home - Visual Studio Code 2021_03_27 20_54_40.png
Project Wizardが表示されるので、任意のプロジェクト名を設定し、BoardはM5Stack Core2を選択し、Finishi。
PIO Home - Visual Studio Code 2021_03_27 20_55_20.png
(なぜかプロジェクト生成に結構時間がかかった。)
PIO Home - Visual Studio Code 2021_03_27 20_58_56.png
この画面のようにプロジェクトファイルが生成されればOK。後のサンプルではsrc/main.cppを編集する。
platformio.ini - Core2Test1 - Visual Studio Code 2021_03_27 21_05_03.png

必要なライブラリのインストール

次に、生成したプロジェクトに必要なライブラリを関連付ける。
PIO HomeからLibrariesでM5Core2を検索する。
platformio.ini - Core2Test1 - Visual Studio Code 2021_03_27 21_06_00.png
M5Core2を選択し、Add to Projectをクリック。
platformio.ini - Core2Test1 - Visual Studio Code 2021_03_27 21_06_09.png
2つめのドロップダウンリストから、先程生成したプロジェクトを選択し、Addをクリック。
platformio.ini - Core2Test1 - Visual Studio Code 2021_03_27 21_06_22.png
もうひとつ、画面表示用ライブラリのLovyanGFXも追加する。手順はM5Core2ライブラリの追加と同じ。(画面表示をデフォルトのライブラリで操作する場合は不要。)
PIO Home - Core2Test1 - Visual Studio Code 2021_03_27 21_09_22.png
ここまでの設定が正しく出来ていれば、最初に生成したプロジェクト内のplatformio.iniがこのように変化している。
platformio.ini - Core2Test1 - Visual Studio Code 2021_03_27 21_11_53.png

ビルドと実機への書き込み

準備

M5Stack公式からCP2104 Driverをダウンロードしてインストール(環境によってはなくても動くかも?)。
Download _ m5stack-store - Google Chrome 2021_03_27 21_27_52.png
今回の環境は64bit版Windows 10なのでCP210xVCPInstaller_x64_v6.7.0.0.exeをインストールした。
CP210x_VCP_Windows 2021_03_27 21_33_52.png
M5Core2をUSBケーブルでPCに接続、電源をONにする。
R0000542_.jpg

サンプルコード1(画面表示とバッテリー情報読み出し)

バッテリ電圧と電流値をライブラリで読み出し、LovyanGFXを使って画面に表示する。
充電中は常時表示、バッテリー動作中は約500ミリ秒で画面ONとOFFを繰り返す。

main.cpp
#include <M5Core2.h>

#define LGFX_M5STACK_CORE2
#include <LovyanGFX.hpp>

static LGFX lcd;

void setup()
{
  M5.begin(true, true, true, true);

  lcd.init();
  lcd.setFont(&fonts::lgfxJapanGothic_28);
  lcd.setBrightness(128);
  lcd.setCursor(0, 128);
  lcd.println("はろーテスト壱");
}

void loop()
{
  M5.update();

  float batVol = M5.Axp.GetBatVoltage();
  float batCur = M5.Axp.GetBatCurrent();

  lcd.setCursor(0, 156);
  lcd.printf("Baterry: %1.3f\nCurrent: %.3f\n", batVol, batCur);

  if (batCur < 0) {
    delay(500);
    lcd.setBrightness(0);
    lcd.sleep();
    delay(500);
    lcd.wakeup();
    lcd.setBrightness(128);
  }
}

このコードをプロジェクトのsrc/main.cppに置き、ビルドしてみる。
PlatformIOのアイコンをクリックして、PROJECT TASKSからm5stack-core2→General→Build、ターミナルでSUCCESSが表示されることを確認。
platformio.ini - Core2Test1 - Visual Studio Code 2021_03_27 21_50_36.png
今度はUpload(エラーが出る場合はM5Stack側の電源が入っていること、USBが接続されていることを確認)。
main.cpp - Core2Test1 - Visual Studio Code 2021_03_27 21_57_06.png
書き込みが完了すると自動でリセットがかかり、この画面が表示される。
ひらがな、カタカナ、漢字も表示できるが、機種依存文字はバグる。
バッテリが正常なら電流値は正の値(充電電流?)になる。バッテリが抜けていると電流値は0。
R0000545_.jpg
USBケーブルを外すと電流値が負の値(消費電流)になる。
R0000546_.jpg

サンプルコード2(Wifi接続とNTPによるRTCへの時刻設定)

M5Core2はRTCを持っているので、時刻を設定すれば電源OFF時やDeep Sleep時に時刻が保持される。
Wifi接続し、NTPを使って時刻同期する。
※こちらの記事を参考にしました。
https://qiita.com/kaoruka/items/b36c99fb124fea0d5d24

main.cpp
#include <M5Core2.h>
#include <time.h>
#include <WiFi.h>

#define LGFX_M5STACK_CORE2
#include <LovyanGFX.hpp>

static LGFX lcd;

char ssid[] = "*****************";
char pass[] = "*****************";

const char* ntpServer = "ntp.jst.mfeed.ad.jp";
const long  gmtOffset_sec = 9 * 3600; // Offset: +9Hour (JST)
const int   daylightOffset_sec = 0;   // Summer time = no
static const char *wd[7] = {"Sun","Mon","Tue","Wed","Thr","Fri","Sat"};

RTC_DateTypeDef RTC_DateStruct;
RTC_TimeTypeDef RTC_TimeStruct;

void setNTP2RTC(){
    struct tm timeinfo;
    configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
    while (!getLocalTime(&timeinfo)) {
      delay(1000);
    }

    //Over write
    M5.Rtc.GetDate(&RTC_DateStruct);
    RTC_DateStruct.Year = timeinfo.tm_year + 1900;
    RTC_DateStruct.Month = timeinfo.tm_mon + 1;
    RTC_DateStruct.Date = timeinfo.tm_mday;
    RTC_DateStruct.WeekDay = timeinfo.tm_wday;
    M5.Rtc.SetDate(&RTC_DateStruct);

    //Over write
    M5.Rtc.GetTime(&RTC_TimeStruct);
    RTC_TimeStruct.Hours = timeinfo.tm_hour;
    RTC_TimeStruct.Minutes = timeinfo.tm_min;
    RTC_TimeStruct.Seconds = timeinfo.tm_sec;
    M5.Rtc.SetTime(&RTC_TimeStruct);
}

int wifiConnect() {
  int con_count = 0;
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    lcd.print(".");
    con_count++;
    if(con_count >= 20){
      break;
    }
  }
  if(con_count < 20){
    lcd.print("\nWiFi connected.");
  }else{
    lcd.print("\nWiFi did not connect.");
  }
  lcd.print("\nIP=");
  lcd.print(WiFi.localIP());
  return con_count;
}

void setup() {
  M5.begin(true, true, true, true);
  lcd.init();
  lcd.setFont(&fonts::lgfxJapanGothic_28);
  lcd.setBrightness(128);
  lcd.setCursor(0, 0);

  if (wifiConnect() < 20) {
    setNTP2RTC();
  }
}


void loop() {
  lcd.setCursor(0, 100);
  M5.Rtc.GetDate(&RTC_DateStruct);
  M5.Rtc.GetTime(&RTC_TimeStruct);
  lcd.printf("%04d.%02d.%02d %s\n", RTC_DateStruct.Year, RTC_DateStruct.Month, RTC_DateStruct.Date, wd[RTC_DateStruct.WeekDay]);
  lcd.printf("%02d:%02d:%02d", RTC_TimeStruct.Hours, RTC_TimeStruct.Minutes, RTC_TimeStruct.Seconds);
  delay(500);
}

コード内のssid[]とpass[]には、接続したいWifiのSSIDとパスワードを設定すること。
5GHz帯の無線LANには接続できなかった。ESP32-D0WDQ6-V3のデータシートに以下の記載があるので2.4GHz帯でないとダメかもしれない。
• 802.11 b/g/n
• 802.11 n (2.4 GHz), up to 150 Mbps

Wifiに接続できるとNTPで時刻が同期され、以下の画面が表示される。
R0000548_.jpg

サンプルコード3(GPIOとADC)

GPIOとADCはよくあるArduinoと同じ書き方で制御できる。
(GPIOの35と36はもともとADC用に設定されているが、他のGPIOをADCに設定する場合は追加で何か設定が要るかも知れない。未調査。)

main.cpp
#include <M5Core2.h>

#define LGFX_M5STACK_CORE2
#include <LovyanGFX.hpp>

static LGFX lcd;

void setup() {
  M5.begin(true, true, true, true);
  lcd.init();
  lcd.setFont(&fonts::lgfxJapanGothic_28);
  lcd.setBrightness(128);
  lcd.setCursor(0, 0);

  //Initialize GPIO
  pinMode(19, OUTPUT);
  digitalWrite(19, LOW);
}


void loop() {
  uint16_t pin35ADC = analogRead(35);
  float pin35vol = (float)pin35ADC *  3.3 / 4096;
  uint16_t pin36ADC = analogRead(36);
  float pin36vol = (float)pin36ADC *  3.3 / 4096;

  lcd.setCursor(0, 100);
  lcd.printf("ADC35: %1.4f[V]\nADC36: %1.4f[V]\n", pin35vol, pin36vol);

  //Toggle GPIO
  digitalWrite(19, LOW);
  delay(400);
  digitalWrite(19, HIGH);
  delay(100);
}

動作画面。自作拡張ボードでADCに信号入力している。(拡張ボードの話は別記事で書くかも。)
R0000549_.jpg

サンプルコード4(マイクロSDへのデータ書き込み)

マイクロSDカードは、公式には16GBまで対応している。実験した範囲では32GBも認識した。
マイクロSDカードはあらかじめFAT32でフォーマットしておく。

以下のサンプルは、
・setupでRTCから時刻を読み出し、YYYYMMDD_HHMMSS.csvという命名規則でファイル生成
・loopではRTCから定期的に時刻を読み出して上記のファイルに追記
という動作をしている。
※あらかじめサンプルコード2でRTCを設定しておく必要がある。

main.cpp
#include <M5Core2.h>

#define LGFX_M5STACK_CORE2
#include <LovyanGFX.hpp>

static LGFX lcd;

RTC_TimeTypeDef RTCtime_Now;
RTC_DateTypeDef RTCDate_Now;
char fileStrbuff[64];
char timeStrbuff[64];

File file;

void setup()
{
  M5.begin(true, true, true, true);

  lcd.init();
  lcd.setFont(&fonts::lgfxJapanGothic_28);
  lcd.setBrightness(128);

  //SDカードが存在するかチェック
  if (!SD.begin()) {
    lcd.println("ERROR: SD CARD.");
    while (1);
  }

  //RTCで起動した時刻を取得し、ファイル名に使用する
  M5.Rtc.GetTime(&RTCtime_Now);
  M5.Rtc.GetDate(&RTCDate_Now);
  //ファイルは絶対パスで指定するので、/(ファイル名)、/が無いとエラーになる
  sprintf(fileStrbuff,"/%04d%02d%02d_%02d%02d%02d.csv",
        RTCDate_Now.Year,RTCDate_Now.Month,RTCDate_Now.Date,
        RTCtime_Now.Hours,RTCtime_Now.Minutes,RTCtime_Now.Seconds
        );

  //ファイル生成(チェック)
  file = SD.open(fileStrbuff, FILE_WRITE);
  if (!file) {
    lcd.println("ERROR: OPEN FILE.");
    while (1);    
  }
  file.close();
}

void loop()
{
  M5.update();

  //現在時刻取得
  M5.Rtc.GetTime(&RTCtime_Now);
  M5.Rtc.GetDate(&RTCDate_Now);
  sprintf(timeStrbuff,"%04d/%02d/%02d %02d:%02d:%02d",
        RTCDate_Now.Year,RTCDate_Now.Month,RTCDate_Now.Date,
        RTCtime_Now.Hours,RTCtime_Now.Minutes,RTCtime_Now.Seconds
        );

  //生成したファイルが存在することを確認し、タイムスタンプを書き込み
  //安全対策で毎回ファイルを開いて閉じているが、別途クローズ処理するならsetupでオープンしたまま書き込み続けて良い
  if (SD.exists(fileStrbuff)) {
    file = SD.open(fileStrbuff, FILE_APPEND);
    file.println(timeStrbuff);
    file.close();
  } else {
    //途中でSDが抜けたor認識エラー
    lcd.println("ERROR: FILE IS MISSING!");
    while (1);
  }

  lcd.setCursor(0, 100);
  lcd.println(timeStrbuff);

  delay(1000);
}

マイクロSDが正しく挿さっていれば、この画面のように時刻を表示し、同時にデータを書き込み続ける。
R0000550_.jpg
一度電源を切ってSDカードを抜き、PCで確認するとこのようなファイルが生成されている。
image.png

15
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
21