M5Stack ESP32 PSRAM Timer Camera X (OV3660)

概要

長らく日本未発売だったTimer Camera Xが日本でも販売されました。技適は取得していたのですが、なぜか発売されていなかったんですよね。

本当は日本発売前に購入して手元にあったのですが、なかなか触れなかったので紹介が遅れてしまいました。

商品

こちらは、M5シリーズではないみたいですね。M5と名前についていない商品で、コアでもユニットとも表記がありません。公式ストアだと何故かユニットに分類されていますが、カメラ系はESP32が中に入っているのでユニットではないと思うんですよね。

中身です。この商品にはUSBケーブルが入っていますね。マウンターも2つ同梱されています。

裏側です。技適マークがちゃんと入っていますね。下にあるGrove端子はGPIO3と13でちょっと中途半端です。

本体には電源ONボタンしか内容に思えますが、実は上記の穴がリセットボタンです。

他のシリーズと比べてみました。左の白いのがM5CAMERA Fで、黒いのがM5CAMERA、灰色のが今回のTimer Xで、オレンジがM5StickCです。

M5CAMERA Fのみ厚みが分厚く、それ以外はM5StickCと同じ大きさです。ただし、黒いM5CAMERAはレゴ用の耳がついているので横幅が大きいですね。それ以外の本体はマウンターを使ってレゴなどに固定するように変更されています。

Camera-Tool

出荷時に入っているのはおそらくCamera-Toolのファームウェアだと思います。こちらはWindows専用のアプリと組み合わせて使うものなので、本体だけだと何もできません。

上記にWindows10用のアプリがありますので、ダウンロードします。

Camera-Toolを実行すると上記の画面になります。Timer Xを接続してシリアルポートを設定してから、Burnerボタンを押すとCamera-Tool用のファームウェアが転送されます。

その後にConnectボタンを押すと接続します。

上記のように画面にカメラの映像が表示されれば成功です。

Wi-Fi経由で接続する場合には、シリアルポートの選択の下にある設定マークをクリックして、Wi-Fiアクセスポイントの設定をします。

その後Connect ModeをWifi-Httpを選択してから接続すると、一番上のSERIALがHTTPに変更され、Wi-Fi経由での転送になります。転送速度はHTTP経由の方がシリアルより早いです。

また、この描画するアプリはAndroid用アプリもAPK形式で用意されています。。。ストア経由じゃないので、わざわざ入れてまで使うのはおすすめしません。

Arduino環境

ライブラリは「Timer CAM」で検索すると出てくると思います。

web_cam

カメラ系によく使われている標準的なブラウザでのビデオ表示スケッチ例です。このボードはM5StickC系統に属しているので、シリアルドライバーはArduino IDEをインストールすると同時に入っていると思います。ただし、転送速度が特殊なので921600などのよく使われている速度では転送ができません。またPSRAMを搭載しているのですが、フラッシュの容量は4MBになります。

ビルドで利用する設定は上記になります。ESP32 Wrover ModuleというPSRAMと搭載しているボードを選択し、アップロード速度を115200、パーティションサイズをNo OTAでアプリ3MBのHuge APPに設定します。

ちなみにこのアップロード速度はものすごく遅いので、あまり実用的な開発はできません。

上記のM5Stack社の提供しているArduino開発環境を利用することでTimer Camを選択することができるようになります。

こちらの設定ですと転送速度が高くなっているので、かなり快適です。とはいえ、別環境を入れるとちょっと不安だって人は、転送速度だけを追加することも可能です。

ボード定義の追加

  • C:\Users\%username%\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.4

Windows環境の人は上記に設定ファイルが入っています。boards.txtがボードの設定になります。このファイルを直接編集すると、壊したときに復旧できなくなるので、boards.local.txtというファイルを作成して、差分だけ設定します。

esp32wrover.menu.UploadSpeed.1500000.windows=1500000
esp32wrover.menu.UploadSpeed.1500000.upload.speed=1500000

今回はESP32 Wrover Moduleの転送速度に1500000を追加します。この設定はboards.txtを見て該当部分を推測して、設定をしました。

この状態でArduino IDEを再起動すると、ボード設定で1500000が選択できるようになっているはずです。これでかなり快適な開発ができると思います。

m5lite.name=M5Lite

m5lite.upload.tool=esptool_py
m5lite.upload.maximum_size=1310720
m5lite.upload.maximum_data_size=327680
m5lite.upload.wait_for_upload_port=true

m5lite.serial.disableDTR=true
m5lite.serial.disableRTS=true

m5lite.build.mcu=esp32
m5lite.build.core=esp32
m5lite.build.variant=esp32
m5lite.build.board=M5LITE

m5lite.build.f_cpu=240000000L
m5lite.build.flash_size=4MB
m5lite.build.flash_freq=40m
m5lite.build.flash_mode=dio
m5lite.build.boot=dio
m5lite.build.partitions=default
m5lite.build.defines=

m5lite.menu.PSRAM.disabled=Disabled
m5lite.menu.PSRAM.disabled.build.defines=
m5lite.menu.PSRAM.enabled=Enabled
m5lite.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue

m5lite.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)
m5lite.menu.PartitionScheme.default.build.partitions=default
m5lite.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS)
m5lite.menu.PartitionScheme.defaultffat.build.partitions=default_ffat
m5lite.menu.PartitionScheme.default_8MB=8M Flash (3MB APP/1.5MB FAT)
m5lite.menu.PartitionScheme.default_8MB.build.partitions=default_8MB
m5lite.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336
m5lite.menu.PartitionScheme.default_16MB=16M Flash (2 x 6.5 MB app, 3.6 MB SPIFFS)
m5lite.menu.PartitionScheme.default_16MB.build.partitions=default_16MB
m5lite.menu.PartitionScheme.default_16MB.upload.maximum_size=6553600
m5lite.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS)
m5lite.menu.PartitionScheme.minimal.build.partitions=minimal
m5lite.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS)
m5lite.menu.PartitionScheme.no_ota.build.partitions=no_ota
m5lite.menu.PartitionScheme.no_ota.upload.maximum_size=2097152
m5lite.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS)
m5lite.menu.PartitionScheme.noota_3g.build.partitions=noota_3g
m5lite.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576
m5lite.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS)
m5lite.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat
m5lite.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152
m5lite.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS)
m5lite.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat
m5lite.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576
m5lite.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS)
m5lite.menu.PartitionScheme.huge_app.build.partitions=huge_app
m5lite.menu.PartitionScheme.huge_app.upload.maximum_size=3145728
m5lite.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS)
m5lite.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs
m5lite.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080
m5lite.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FAT)
m5lite.menu.PartitionScheme.fatflash.build.partitions=ffat
m5lite.menu.PartitionScheme.fatflash.upload.maximum_size=2097152
m5lite.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9MB FATFS)
m5lite.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB
m5lite.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728

m5lite.menu.CPUFreq.240=240MHz (WiFi/BT)
m5lite.menu.CPUFreq.240.build.f_cpu=240000000L
m5lite.menu.CPUFreq.160=160MHz (WiFi/BT)
m5lite.menu.CPUFreq.160.build.f_cpu=160000000L
m5lite.menu.CPUFreq.80=80MHz (WiFi/BT)
m5lite.menu.CPUFreq.80.build.f_cpu=80000000L
m5lite.menu.CPUFreq.40=40MHz (40MHz XTAL)
m5lite.menu.CPUFreq.40.build.f_cpu=40000000L
m5lite.menu.CPUFreq.26=26MHz (26MHz XTAL)
m5lite.menu.CPUFreq.26.build.f_cpu=26000000L
m5lite.menu.CPUFreq.20=20MHz (40MHz XTAL)
m5lite.menu.CPUFreq.20.build.f_cpu=20000000L
m5lite.menu.CPUFreq.13=13MHz (26MHz XTAL)
m5lite.menu.CPUFreq.13.build.f_cpu=13000000L
m5lite.menu.CPUFreq.10=10MHz (40MHz XTAL)
m5lite.menu.CPUFreq.10.build.f_cpu=10000000L

m5lite.menu.FlashMode.qio=QIO
m5lite.menu.FlashMode.qio.build.flash_mode=dio
m5lite.menu.FlashMode.qio.build.boot=qio
m5lite.menu.FlashMode.dio=DIO
m5lite.menu.FlashMode.dio.build.flash_mode=dio
m5lite.menu.FlashMode.dio.build.boot=dio
m5lite.menu.FlashMode.qout=QOUT
m5lite.menu.FlashMode.qout.build.flash_mode=dout
m5lite.menu.FlashMode.qout.build.boot=qout
m5lite.menu.FlashMode.dout=DOUT
m5lite.menu.FlashMode.dout.build.flash_mode=dout
m5lite.menu.FlashMode.dout.build.boot=dout

m5lite.menu.FlashFreq.80=80MHz
m5lite.menu.FlashFreq.80.build.flash_freq=80m
m5lite.menu.FlashFreq.40=40MHz
m5lite.menu.FlashFreq.40.build.flash_freq=40m

m5lite.menu.FlashSize.4M=4MB (32Mb)
m5lite.menu.FlashSize.4M.build.flash_size=4MB
m5lite.menu.FlashSize.8M=8MB (64Mb)
m5lite.menu.FlashSize.8M.build.flash_size=8MB
m5lite.menu.FlashSize.8M.build.partitions=default_8MB
m5lite.menu.FlashSize.2M=2MB (16Mb)
m5lite.menu.FlashSize.2M.build.flash_size=2MB
m5lite.menu.FlashSize.2M.build.partitions=minimal
m5lite.menu.FlashSize.16M=16MB (128Mb)
m5lite.menu.FlashSize.16M.build.flash_size=16MB

m5lite.menu.UploadSpeed.115200=115200
m5lite.menu.UploadSpeed.115200.upload.speed=115200
m5lite.menu.UploadSpeed.256000.windows=256000
m5lite.menu.UploadSpeed.256000.upload.speed=256000
m5lite.menu.UploadSpeed.230400.windows.upload.speed=256000
m5lite.menu.UploadSpeed.230400=230400
m5lite.menu.UploadSpeed.230400.upload.speed=230400
m5lite.menu.UploadSpeed.250000=250000
m5lite.menu.UploadSpeed.250000.upload.speed=250000
m5lite.menu.UploadSpeed.460800.linux=460800
m5lite.menu.UploadSpeed.460800.macosx=460800
m5lite.menu.UploadSpeed.460800.upload.speed=460800
m5lite.menu.UploadSpeed.500000=500000
m5lite.menu.UploadSpeed.500000.upload.speed=500000
m5lite.menu.UploadSpeed.512000.windows=512000
m5lite.menu.UploadSpeed.512000.upload.speed=512000
m5lite.menu.UploadSpeed.750000=750000
m5lite.menu.UploadSpeed.750000.upload.speed=750000
m5lite.menu.UploadSpeed.921600=921600
m5lite.menu.UploadSpeed.921600.upload.speed=921600
m5lite.menu.UploadSpeed.1500000=1500000
m5lite.menu.UploadSpeed.1500000.upload.speed=1500000

m5lite.menu.DebugLevel.none=None
m5lite.menu.DebugLevel.none.build.code_debug=0
m5lite.menu.DebugLevel.error=Error
m5lite.menu.DebugLevel.error.build.code_debug=1
m5lite.menu.DebugLevel.warn=Warn
m5lite.menu.DebugLevel.warn.build.code_debug=2
m5lite.menu.DebugLevel.info=Info
m5lite.menu.DebugLevel.info.build.code_debug=3
m5lite.menu.DebugLevel.debug=Debug
m5lite.menu.DebugLevel.debug.build.code_debug=4
m5lite.menu.DebugLevel.verbose=Verbose
m5lite.menu.DebugLevel.verbose.build.code_debug=5

ちなみに、私はちょっと長いですが、上記の設定を追加しています。

こちらは全部入りの設定で、どのボードでも利用できるようになります。とはいえ、たとえばWire.begin()などと引数無しで呼び出した場合には、ボード設定の標準ピン番号が利用されます。ボード設定は正しいものを利用したほうが安全ではあります。個人的にはピンを自分で設定するほうが好きなのですが、無指定のほうが初学者には優しいと思います。

const char* ssid = "ssid";
const char* password = "********";

さて、かなり脱線してしまいましたがスケッチ例で上記のWi-Fiアクセスポイントの設定のみ変更してビルドする必要があります。典型的なスケッチ例だと接続できない場合にはESP32自体がソフトAPになって、スマホなどから接続するのですがこのスケッチ例はWi-Fiルーターなどに接続する前提になっています。

Connect to ssid, key
..
WiFi connected
Starting web server on port: '80'
Starting stream server on port: '81'
Camera Ready! Use 'http://192.168.10.2' to connect

転送が終わると、シリアルモニタに上記のような文字列が表示されます。このURLをブラウザで開きます。

上記のような画面が表示されると思います。一番下にスクロールすると、ストリーミングで動画を表示するか、写真を取得するかのボタンがあります。

wakeup

タイマー動作するスケッチ例です。LEDの明るさが徐々に変わってから電源オフ。5秒後に再起動します。このボードはM5PaperやM5Stack CoreInkと同じような電源管理になっています。

上記の電源と同じような感じになっています。電源保持はGPIO33ですね。GPIO33をLOWにすることで電源OFFになります。ただしUSB接続している場合には電源OFFはできません。

シリアルモニタにはバッテリー電圧とRTCの日時が表示されますが、RTCを設定するスケッチ例は入っていませんね。

rtc_set_ntp

#include "bmm8563.h"
#include <WiFi.h>

const char* ntpServer = "time.cloudflare.com";

void setup() {
  // Init Serial
  Serial.begin(115200);
  delay(50);

  // Connect to an access point
  WiFi.begin();                 // Connect to the access point of the last connection
  //WiFi.begin("SSID", "KEY");  // Or, Connect to the specified access point

  Serial.print("Connecting to Wi-Fi ");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println(" CONNECTED");

  // Set ntp time to local
  configTime(9 * 3600, 0, ntpServer);

  // Init RTC
  bmm8563_init();

  // Get local time
  struct tm timeInfo;
  if (getLocalTime(&timeInfo)) {
    // Set RTC
    rtc_date_t date;
    date.year    = timeInfo.tm_year + 1900;
    date.month   = timeInfo.tm_mon + 1;
    date.day     = timeInfo.tm_mday;
    date.hour    = timeInfo.tm_hour;
    date.minute  = timeInfo.tm_min;
    date.second  = timeInfo.tm_sec;
    bmm8563_setTime(&date);
  }
}

void loop() {
  // Get RTC
  rtc_date_t date;
  bmm8563_getTime(&date);

  // Print RTC
  Serial.printf("%04d/%02d/%02d %02d:%02d:%02d\n",
                date.year,
                date.month,
                date.day,
                date.hour,
                date.minute,
                date.second
               );

  // Wait
  delay(1000);
}

RTCをNTPから設定するスケッチを書いてみました。web_camを実行している場合には、Wi-Fi情報が保存されていますので、WiFi.begin()で接続することで最後の情報を使って接続します。Wi-Fi設定はこのように最初に一度他のスケッチでWiFi.begin(“SSID”, “KEY”)などで接続して、実際の利用はWiFi.begin()とスケッチにはSSIDを書かないほうが好ましいと思います。

また、このライブラリはM5というクラスが出てきません。他のライブラリとはかなり違っているので注意してください。RTCはBMM8563でM5StickCなどと同じなのですが、構造体の名前なども違うのでソースの流用が面倒です。この辺を統一してほしいのですが、なかなか難しいですね。

電源OFF

ちなみに、タイマー起動系のファームウェアを転送している状態では電源を切ることはできません。自動起動して動いて止まるを繰り返してバッテリーがなくなるまで動きます。

保管する場合にはタイマー起動しないスケッチを転送したあとにUSBを抜いてから、bat_disable_output関数で電源OFFにします。

#include "camera_pins.h"
#include "led.h"
#include "battery.h"

void setup() {
  bat_init();
  led_init(CAMERA_LED_GPIO);
  led_brightness(1024);
  bat_disable_output();
}

void loop() {
  led_brightness(1024);
  delay(100);
  led_brightness(0);
  delay(100);
}

えーっと、、、電源OFFにならないですね。私だけ?

#include "camera_pins.h"
#include "led.h"

void setup() {
  led_init(CAMERA_LED_GPIO);
  led_brightness(1024);
}

void loop() {
  led_brightness(1024);
  delay(100);
  led_brightness(0);
  delay(100);
}

上記の状態だとそもそもBAT_OUTPUT_HOLD_PINの制御をやっていないので、USBを抜くと電源OFFのハズですがだめです。

んー、HIGHになっているところを全部LOWに変更してみましたが電源OFFにはなりません。設計がおかしいのか、私の端末がおかしいのか、、、

*以下追記

#include "camera_pins.h"
#include "led.h"
#include "bmm8563.h"
#include "battery.h"

void setup() {
  // Init
  bat_init();
  bmm8563_init();
  led_init(CAMERA_LED_GPIO);

  // Test LED
  led_brightness(1023);
  delay(1000);

  // Halt
  bat_disable_output();
}

void loop() {
  // USB Only
  led_brightness(1023);
  delay(100);
  led_brightness(0);
  delay(100);
}

RTCの初期化をしていませんでした。RTCが通知フラグがたったままだと電源OFFにできません。bmm8563_init()は必ず呼び出すようにしてください。bat_init()を呼び出さない場合にはバッテリー動作をしないことになります。USB接続だけで使う場合には呼び出す必要はありませんが、通常は呼び出しておくことをおすすめします。

上記スケッチを動かすとわかるのですが、転送するとLEDが1秒光ってからブリンクします。その状態でUSBを抜くとブリンクが止まって電源OFFになります。そして本体の電源を長押しすると起動します。思ったより長い時間押していないと起動しません。内部的にはESP32が起動してbat_init()が呼び出されるまで押している必要があります。

  • 電源ボタンが押された状態
  • RTCの通知フラグ
  • BAT_OUTPUT_HOLD_PIN(GPIO33)がHIGH
  • USB接続で電源供給されている

ざっくり上記の条件のどれかが達成している場合に電源ONが維持されます。すべての条件が達成されていない場合にのみ電源OFFになります。

本当はbat_disable_output()で電源落とす前に、RTCの通知を初期化しないと通知上がったままで電源OFFにならないって状況が発生すると思います。

まとめ

製品的には過去のカメラにバッテリーとRTCが追加されていますが、価格は同じぐらいです。比較的使いやすい製品だと思いますが、ライブラリ的にはちょっと不満です。ボード選択もPSRAMを搭載しつつ、フラッシュが4MBなのでM5Stack Fireの設定が使えません。M5StickCだとPSRAMを搭載していないのでM5Stack版のArduino開発環境を使うのがおすすめです。

コメント

  1. 匿名 より:

    回路図上 GPIO37が電源ボタンに繋がっていて期待したのですが、基板上とESP32内部どちらもpullup抵抗がないためたぶん使えません。非常に残念です!

  2. そーたメイ より:

    たぶんESP32内部のpullupを期待して基板を作ってしまい、結果的に使えなかったのではないでしょうか。ポート仕様にもGPIO37は記載されていません。次のロットで修正されていることを期待してます。

  3. そーたメイ より:

    あとFBで書かせて頂いた下記症状について、私の環境だとM5Atomでも起きる(しかもM5Atomの場合ぱっと見分からないためLEDが怪しく光るTimerCameraXよりも分かりにくい)のですが、この症状って私の環境だけなのでしょうか?

    起動しない ≒ BootMode=burnに入ってしまうことがある
     FW書き込み直後やUSB接続直後にBootMode=burnに入ってしまうことがあります。RESETでは復旧せず、ケーブル抜き差しで復旧します。BootMode=burnに入っていると青LEDがうっすら光るので、そのときはケーブル抜き差しして下さい。
    AtomとTimerCameraXはUSB-UARTマイコンCH522Tが入っておりこのマイコンがBootMode制御をしています。RESETボタンではこのUSB-UARTマイコンがRESETできないためです。

タイトルとURLをコピーしました