VSCode (PlatformIO) で M5StickC の開発をするぞ!!!

M5StickC を使った開発をしたいけど Arduino の IDE は使いたくないな〜 もっとモダンな開発環境を使いたいな〜っと思っていたところで PlatformIO という物を知ったのでこれを使って開発することにしました。

なんと VSCode の extension もあるので今回はそれを使った開発方法について説明したいと思います。

※ 今回は M5StickC を前提で話しますが、M5Stack でもほとんど同じです(どっちでもいい内容のときは M5 と記載します)。

開発環境構築

インストール方法にしたがって Extension をインストールします。

プロジェクト作成

  1. VSCode の左側の Acitivity Bar から Platform IO (以下 PIO) の Extension を開きます
  2. Projects & Configuration を開きます
  3. Create New Project をクリックします

f:id:mironal:20210827174307p:plain

プロジェクトはこんな感じで作ります。

  • Name: プロジェクト名
  • Board: M5StickC
  • Framework: Arduino

f:id:mironal:20210827174617p:plain

そしたら platformio.ini を以下のように編集します.

[env:m5stick-c]
platform = espressif32
board = m5stick-c
framework = arduino
lib_deps = m5stack/M5StickC@^0.2.3 ; 多分これと
monitor_speed = 115200 ;これを追加する必要があります

lib_deps

lib_deps に関しては PIO の Extension のLibraries から M5StickC と検索して Add to Project から追加しても大丈夫です.

f:id:mironal:20210827175016p:plain

monitor_speed

monitor_speed は後で Upload & Monitor などでシリアルコンソールを使う場合は設定が必要ですが、特に使用しない場合はしなくてもいいです。

開発作業

src/main.cpp にコードを書いて M5StickC で実行する場合は PIO の画面から Upload を押すとコンパイル後にアップロードされます(もちろん M5StickC はつないでおいてください)。

アップロード後にシリアルコンソール(モニター)に接続したい場合は `Upload and Monitor' で実行してください。

f:id:mironal:20210827175229p:plain

テスト

テストコードも書くことができます。

テストはデバイス上(M5StickC)でのテスト(Test Type: Embedded)の他にも自分の開発している PC 上で動かすテスト(Test Type: Desktop) を書くことができます。

※ Desktop のテストはデバイスに依存した部分はテストできません(コンパイルが通らない)。

テストは公式ドキュメント のほか、以下のサンプルプロジェクトを参考にするのがわかりやすいです。

github.com

以下のあたりを参考にするとわかると思います。

  • test ディレクトリ以下の構造
    • test_desktop 以下が Desktop のテストです
  • platformio.ini の内容

Tips

以下は僕がいくつかのものを作ったときに知ったノウハウです。

今まで M5StickC で作ったものとしては

  1. 常時起動しておいてインターホンの音を解析して、インターホンが鳴ったら LINE に通知する君
  2. ある特定の日付までの残日数を表示するちっちゃいモニタ

があります。

WiFi への接続方法

GitHub を含めネット上のコードを見るとよくこのように SSID と PASSWORD を記載しているコードを見かけます。こうやってハードコードしてあるとなにかのミスで自分の家の SSID や PASSWORD が流出してしまって危ないですよね。

#include <M5StickC.h>
#include <WiFi.h>

#define SSID "XXXX" // 危ない
#define PASSWORD "YYYYY" // 超危ない

void setup()
{
  M5.begin();
  M5.Lcd.setRotation(1);

  // WiFi 接続
  WiFi.begin(SSID, PASSWORD);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    M5.Lcd.print(".");
  }
}

実は、一度 WiFi.begin(SSID, PASSWORD); で書き込まれた情報はM5のメモリ内(正確には ESP32 の NVS(不揮発メモリ))に保存されるので2回目からは引数無しで WiFi.begin(); と呼ぶだけでいいのです。

詳しい処理は WiFiSTA.cppbegin の内の処理を読むと esp_wifi_set_configesp_wifi_get_config を使って WiFi 設定の保存と取得をしていることがわかります。

なので以下のようなコードで良くなります。実装するアプリケーションにもよりますが、公開する前提のコードを安全に書くためには↑に示すような SSID と PASSWORD を含む非公開なコードでまず一度 M5 に書き込んだ後に↓のような公開用コードを使って開発を進めていくのが安全かと思います(要するにずっと SSID とかがコード上にベタ書きされていなければいいと思います)。

#include <M5StickC.h>
#include <WiFi.h>

void setup()
{
  M5.begin();
  M5.Lcd.setRotation(1);

  // WiFi 接続
  WiFi.begin();
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    M5.Lcd.print(".");
  }
}

ちなみの WiFi 情報を保存されっぱなしにしたくない場合は WiFi 切断時に WiFi.disconnect(false, true /*こっちが削除のフラグ*/); と呼ぶと削除できます.

NTP を使った時刻同期

M5Stick は起動直後は内部の時間は1970年1月1日午前0時0分0秒(UNIXエポック)になっているので、時刻を使う場合は何らかの方法で正しい時刻を取得する必要があります。

インターネットへの接続がある状態なら NTP を使ってかんたんに時刻同期ができます。

以下のコードは configTzTime を使って NTP を使った時刻同期をしています(configTime よりもおすすめ)。

void syncTime()
{

  configTzTime("JST-9", "ntp.nict.jp");

  // 同期完了を待つ
  while (sntp_get_sync_status() != SNTP_SYNC_STATUS_COMPLETED)
  {
    delay(1);
  }
}

M5StickC は RTC がついているので同期した結果を書き込むこともできます。 一度 RTC に時刻を書き込んだあとは起動時に Wifi 接続ができない場合は RTC から時刻を読み込むことで正しい時刻を使うこともできます。

でもインターネットに普通に接続できている環境ならいちいち RTC を使わなくても毎回 ntp から取得すればいいと思います(試していないですが1時間ごとに同期されるようです)。

マルチスレッドプログラミング

M5 は通常マルチコアなのでマルチコアを使ったプログラムも作れます。

以下にコード例を示します。

ポイントとしては M5 (Arduino) はマルチコアの場合、1番目のコア(0番から始まる)で setuploop が実行されます。つまり0番目のコアは空いているので 0 番目のコアでタスクを実行します。

// 別のコアで動かしたい処理
void someTask(void *pvParameters)
{
    while(true) {
        delay(1); // これがないと Watchdoc で再起動になってしまう
    }

    // loop しないで終わる系のタスクの場合は以下のメソッドで task を削除する必要がある
    // vTaskDelete(NULL);
}

void setup() 
{

    // 初期化処理...

    // タスク起動
    // 最後の引数の 0 はコア版後の指定(= 0番目のコアでタスク実行)
    xTaskCreatePinnedToCore(someTask, "someTask", 8192, NULL, 1, NULL, 0);
}

Deep Sleep

M5 は Light Sleep や Deep Sleep という機能があり、一部の機能を停止することで省電力にすることができます。

Deep Sleep がよく使われるようなので紹介しておきます。

以下の関数を適当な箇所で呼び出すと即座に Deep Sleep します。簡単ですね。

void startDeepSleep()
{
  // BtnA (M5 って書いてある大きいボタン) が押されたら起動
  pinMode(GPIO_NUM_37, INPUT_PULLUP);
  esp_sleep_enable_ext0_wakeup(GPIO_NUM_37, LOW);
  M5.Axp.SetSleep(); // display off
  esp_deep_sleep_start();
}

FFT

M5StickC はマイクが付いているので取得した音声を FFT することもできます。

実はこれは購入直後に入っているファクトリーテストのプログラムに入っています。

結構複雑ですがコピペして使うこともできるので興味のある方は見てみてください。

github.com

まとめ

VSCode を使った M5StickC の開発方法を紹介しました。

さらに僕の開発経験の中からいくつかの Tips を紹介しました。

これから開発をする人の参考になれば幸いです。