M5Stack NanoC6購入

概要

ESP32-C6搭載の小型ボードのNanoC6が発売されたので触ってみました。全体的にかなり好印象ですが、まだまだ開発環境が整っていないので真価を発揮するのはまだ先になりそうな予感がします。

製品

M5Stack NanoC6
M5Stack NanoC6は、小指サイズの超小型IoT 開発ボードです。ESP32-C6FH4 を搭載、Wi-Fi 6、Matter、Thread、Zigbeeなどの高度な無線通信方式をサポートします。

今回は中国と日本で同時発売だったのでスイッチサイエンスさんなどで購入するのが良いと思います。

M5Stack NanoC6 Dev Kit
Description The M5NanoC6 is a miniature, low-power IoT development board within the M5Stack development kit series. It i...

本家ストアは上記となります。

外観

プラパッケージにはいっています。内容物は本体のみなのでケーブルなどは付属していません。

裏側です。ATOMと並べてみると圧倒的なサイズの違いがわかると思います。非常に小さくてボタンとUSB、Grove端子、中に青のLEDとRGB LED、横に赤外線LEDのみの構成となります。

Arduino IDEでの開発

Arduino core for the ESP32のバージョン3以降をインストール

ESP32-C6が対応しているArduinoは3以降なのですがまだ正式リリースされていません。そこでベータ版を入れる必要があるのですが、公式ボードマネージャーからベータ版を入れてしまうと安定版を上書きしてしまいます。

  • https://raw.githubusercontent.com/tanakamasayuki/esp32-arduino-test/master/package_esp32_dev_index_3_0_0-alpha3.json

そこで私が作成したボードマネージャーの定義ファイルを使うと、中身は公式と同じものなのですが、環境名を変更してありますので複数バージョンが共存できます。バージョン3が正式リリースされれば楽なのですがもう少し時間がかかりそうです。

ボードマネージャーにURLを追加するとesp32_3.0.0-alpha3が追加されますので「ESP32C6 Dev Module」を選択します。

ボード設定

基本設定のままでもある程度は使えるのですが、「USB CDC On Boot」はEnabledに変更するのがおすすめです。

USB CDC On Boot出力先備考
DisabledUSBSerialSerialに出力すると内蔵の未接続のUARTに出力(見えない)
EnabledSerial既存と同じように利用可能

ESP32-C6はUSBシリアル変換機能を内蔵しているため、外付けUSBシリアル変換チップがNanoC6には搭載されていません。

初回書き込み方法(状態初期化)

NanoC6を接続するとArduino IDEには「LOLIN S3」と認識されます。ボードはUSBシリアルのVIDとPIDを元に表示しているはずですが、ESP32のUSB CDCで利用している共通コードなので複数のボードが同じIDなので特定できないようです。

また、初回出荷時に書き込まれているファームウエアは微妙におすすめ設定ではないので注意してください。Arduino IDEでは選択できないのですがおそらくUSB MODEの設定で書き込みで利用するシリアルポートと、通信で利用するシリアルポートが別になっています。

そのため、そのまま接続したときのシリアルポート番号と、ボタンを押したまま接続したときのシリアルポートが違うはずです。ボタンを押していない場合には書き込みで利用できないシリアルポートで認識されているはずですので、初回書き込み時にはボタンを押したままパソコンにNanoC6を接続してください。

その状態で書き込んだら一度パソコンから抜いて、再度接続しなおしてください。USBモードを変更する場合には電源を入れ直さないと反映されない場合があります。この作業は一度行えば以降は行う必要がありません。

ただ、動きがおかしいなと思ったら上記の操作をして、通常のモードに戻してみてください。

あと普通のESP32には書き込みができる安いUSBハブにつなげていたところ、動作がかなり怪しかったのでなるべくパソコン本体に直接接続した方が安全かもしれません。

GPIOの確認

GPIO用途備考
1Grove AGroveコネクタの外側のPIN
2Grove BGroveコネクタの内側のPIN
3IRHIGHにするとIRの赤外線LEDが光る
7LED(青)HIGHにすると青のLEDが光る
9ボタン通常はHIGHで押すとLOWになる
19EN(RGBPWR)HIGHにするとWS2812に電源供給
20WS2812RGBで色指定できるRGB LED

今回はGroveの端子以外のGPIOについて動作実験をしてみたいと思います。

LEDとIRの動作実験

void setup() {
  Serial.begin(115200);
  pinMode(GPIO_NUM_3, OUTPUT); // IR
  pinMode(GPIO_NUM_7, OUTPUT); // LED
}

void loop() {
   digitalWrite(GPIO_NUM_3, HIGH);
   digitalWrite(GPIO_NUM_7, HIGH);
   Serial.println("HIGH");
   delay(1000);

   digitalWrite(GPIO_NUM_3, LOW);
   digitalWrite(GPIO_NUM_7, LOW);
   Serial.println("LOW");
   delay(1000);
}

Lチカです。青いLEDはわかりやすいですが、IRは目視できないのでスマホなどのインナー側のカメラで確認ができると思います。外側のカメラはIRフィルターが入っており光っているのが確認できないと思いますが、内側のカメラはIRが光っているのが確認できるものが多いはずです。

IRは本来赤外線リモコンなどの送信に利用するのですが、IR送信ライブラリで一番有名な「IRremoteESP8266」がArduino3系に対応していないのでビルドエラーがでて使えません。そして、2系と3系はこの辺のハードウエアを直接叩く機能で変更点が多いのですぐに対応できるかは微妙な気がしています。

M5NanoC6/examples/Basic/ir_nec/ir_nec.ino at main · m5stack/M5NanoC6
Contribute to m5stack/M5NanoC6 development by creating an account on GitHub.

M5Stackのスケッチ例を確認したところ、ライブラリを利用しておらずハードウエアのRMTを直接叩くコードになっていました。そのため、IRリモコンとして利用するのはまだまだ難しいと思います。

ボタンの動作実験

void setup() {
  Serial.begin(115200);
  pinMode(GPIO_NUM_9, INPUT);  // Btn
}

void loop() {
  static int8_t oldBtn = HIGH;

  int8_t btnState = digitalRead(GPIO_NUM_9);
  if (oldBtn != btnState) {
    oldBtn = btnState;
    Serial.printf("btn : %s\n", btnState ? "HIGH" : "LOW");
  }
  delay(1);
}

M5Stackのライブラリもありますが、ボタン操作ぐらいしか使う機能がないのでライブラリを使わなくも大丈夫な場合には直接操作したほうがよいと思います。上記のコードでボタンの状態が変化した場合だけ出力されます。

void setup() {
  Serial.begin(115200);
  pinMode(GPIO_NUM_9, INPUT);  // Btn
}

void loop() {
  static int8_t oldBtn = HIGH;

  int8_t btnState = digitalRead(GPIO_NUM_9);
  if (oldBtn != btnState) {
    oldBtn = btnState;
    if (btnState) {
      // LOW -> HIGH
      Serial.println("wasReleased 離した");
    } else {
      // HIGH -> LOW
      Serial.println("wasPressed 押した");
    }
  }
  delay(1);
}

実際には上記のような処理になると思います。一番利用するのがボタンを押して離したときのwasReleasedイベントだと思います。

RGB LED

void setup() {
  Serial.begin(115200);
  pinMode(GPIO_NUM_9, INPUT);    // Btn
  pinMode(GPIO_NUM_19, OUTPUT);  // EN(RGBPWR)
  pinMode(GPIO_NUM_20, OUTPUT);  // RGBLED

  // ENとBTNを同期
  digitalWrite(GPIO_NUM_19, digitalRead(GPIO_NUM_9));
}

void loop() {
  static int8_t oldBtn = HIGH;
  static uint8_t r = 0;
  static uint8_t g = 0;
  static uint8_t b = 0;

  int8_t btnState = digitalRead(GPIO_NUM_9);
  if (oldBtn != btnState) {
    oldBtn = btnState;
    digitalWrite(GPIO_NUM_19, btnState);
  }

  Serial.printf("EN(%d) R(%3d) G(%3d) B(%3d)\n", btnState, r, g, b);
  neopixelWrite(GPIO_NUM_20, r, g, b);
  r += 64;
  if (r == 0) {
    g += 64;
    if (g == 0) {
      g = 0;
      b += 64;
    }
  }

  delay(1);
}

ちょっと長くなってしまいましたが、RGB LEDはちょっと気をつけて使う必要があります。ENのGPIO_NUM_19をHIGHにしない限り光りません。一般的にはRGBを(0,0,0)で指定して光らせない方法が多いのですが、消費電力を下げるためかGPIO_NUM_19で電源を制御しています。

M5StackのライブラリだとAdafruit_NeoPixelを利用していますが、1つのRGB LEDの場合には標準関数であるneopixelWrite()関数で十分だと思います。ライブラリを使うことで定義済みの色名で指定できるメリットもあります。

PlatformIOでの開発

プラットフォームの更新

まず最初にプラットフォームを最新に更新してください。ここが古いとボード一覧にESP32-C6があるのですが、選択するとボード定義がないとエラーになります。

メニューからだと「Update」になります。一番下の「Upgrade PlatformIO Core」はよく更新するのですがプラットフォームの「Espressif 32」は更新忘れがちになります。

プロジェクト作成

ESP32-C6はPlatformIOだと2つあるのでESP32-C6-DevKitM-1の方を選択してください。Cはフラッシュの容量が大きいので追加設定しないと動きません。Mの方はNanoC6と同じ4MBなのでそのまま動きます。

このままだとFrameworkが「Espidf」しか選択できません。まだPlatformIOではArduino3系のサポートをしていないので選択できないのです。

platformio.iniの編集

[env:esp32-c6-devkitm-1]
platform = espressif32
board = esp32-c6-devkitm-1
framework = arduino
platform_packages =
	platformio/framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git
	platformio/framework-arduinoespressif32-libs @ https://github.com/espressif/esp32-arduino-libs.git#idf-release/v5.1
extra_scripts = pre:custon_hwids.py
build_flags =
    -DARDUINO_USB_CDC_ON_BOOT=1
    -DARDUINO_USB_MODE=1

ここの設定が一番大切です。まずPlatformIOではArduino3系のサポートがないので、platform_packagesで開発中の最新バージョンをURLで直接指定しています。

extra_scriptsはボード定義を上書きするための設定です。「esp32-c6-devkitm-1」のボードは本来ESP-IDFでしか開発することができず、Arduinoが使えません。そのためこの設定を上書きする設定です。

Import("env")

board_config = env.BoardConfig()
board_config.update("frameworks", ["arduino", "espidf"])

上記が実行される「custon_hwids.py」になります。boardのframeworksがespidfしかないものにArduinoを追加する設定をしています。

build_flagsはArduino IDEと同じ設定にするための設定です。ARDUINO_USB_CDC_ON_BOOTとARDUINO_USB_MODEを定義することでUSBで書き込みとシリアル通信が可能になります。

コードの修正

#include <Arduino.h>

void setup()
{
	Serial.begin(115200);
	pinMode(GPIO_NUM_9, INPUT); // Btn
}

void loop()
{
	static int8_t oldBtn = HIGH;

	int8_t btnState = digitalRead(GPIO_NUM_9);
	if (oldBtn != btnState)
	{
		oldBtn = btnState;
		Serial.printf("btn : %s\n", btnState ? "HIGH" : "LOW");
	}
	delay(1);
}

PlatformIOの場合には1行目に「#include <Arduino.h>」をかならず追加してください。拡張子がinoの場合には自動的に追加されるためになくてもエラーになりませんがmain.cppなどのファイルで動かす場合には追加が必要となります。

まとめ

デバイス的には小さくて最低限の機能を搭載して安価とかなりおすすめです。ただし開発環境的にはまだまだだと思いますので注意が必要です。

価格的にはATOM Liteより安いので大量に環境にばらまくタイプのデバイスとして使いやすいと思います。ESP32-C6独自の機能については別途検証してみたいと思います。

コメント

  1. しん より:

    こんにちは、よく参考にさせて頂いています。
    仕様にZigbee が使えるとありますが
    Bluetoothが見当たらないですね
    BLEは使えなくなった・・・ってことでしょか

    • たなかまさゆき より:

      Bluetooth 5は使えますね
      Classicは使えないのでSPP(Serial Port Profile)とかは使えないですが、普通のBLEは利用可能です

  2. しん より:

    ありがとうございます!
    そうなんですか♪
    でも、なんで仕様のとこにBluetooth書かないんでしょ…

    フラッシュの容量からすると
    OTA書き込みとBLEの共存はできんですかね?

    • たなかまさゆき より:

      BLEは書き忘れっぽいですね
      4MBだとプログラムが1.2MなのでBLE使うとたしかに辛いですね

      SPIFFS無しの「No FS」だと2Mが2つ
      min_spiffsだと1.9Mが2つで190KのSPIFFS

      上記だとOTA付きでなんとかいけるかな?

  3. 匿名 より:

    書き忘れ・・・
     えー まじですか。

    Zigbee より ずっと使われてると思うのだけど…

    OTA… そうなんですね。。。