M5StickCの消費電源 その1

液晶の明るさとかを変更しながら、消費電力を計りました。精度はそれほど高くなく、値もふらつくので概算として利用してください。

現時点の情報ですので最新情報はM5StickC非公式日本語リファレンスを確認してください。

画面の明るさ

明るさ消費電力(mA)増減(mA)
072.50
172.50
272.50
372.50
472.50
572.50
672.50
772.70.2
873.91.4
977.75.2
1083.711.2
1191.318.8
12100.728.2

0-6は実際には暗すぎてほぼ見えません。消費電力の変化もありませんので、液晶の最低電圧以下かもしれません。

ボタン(MPU6886)

状態消費電力(mA)増減(mA)
Off72.50
BtnA On72.70.2
BtnB On180.1107.6

えーっと、右側ボタンのBtnBを押すと100mAも消費電力が増えます、、、

回路の抵抗値間違えてない?

ボタン(SH200Q)

状態消費電力(mA)増減(mA)
Off76.50
BtnA On76.70.2
BtnB On76.70.2

もう一台で調べてみましたら、普通の結果です。MPU6886は全部おかしいのか、私の一台だけおかしいのか、誰か検証お願いします。

ちなみに左ボタンはAXPが管理していて、消費電力は特になかったです。

BtnAとBtnBは回路的にプルアップされていて、ボタンを押すとLOWになるので、その分消費電力が発生すると思っていましたが、予想外の結果が出てしまいました。

内蔵赤色LED

状態消費電力(mA)増減(mA)
Off95.60
On116.721.1

20mAぐらいなので、普通ですよね?

内蔵赤外線LED(IR)

状態消費電力(mA)増減(mA)
Off95.90
On121.825.9

赤色LEDより消費電力少しだけ多いんですね。

まとめ

ボタンの結果が意外すぎて、混乱しています。他の項目も少しずつ調べていきたいと思います!

M5StickCのマイクを使ってみる

サンプルスケッチを動かす以上していなかったマイクを触ってみました。もう少し掘り下げて調べる必要がありそうです。

現時点での情報のため、最新情報はM5StickC非公式日本語リファレンスを確認お願いします。

概要

M5StickCにはI2S経由で接続されているマイクが内蔵されています。I2Sからの受信は別タスクで実行され、DMA転送されてバッファに保存されています。

マイクのスペック

型番SPM1423
データシートhttps://github.com/m5stack/M5-Schematic/blob/master/Core/SPM1423HM4H-B.pdf
製造元Knowles Electronics, LLC.
方向無指向性
周波数範囲100Hz ~ 10kHz
感度-22dB ±3dB @ 94dB SPL
S/N比61.5dB
電圧範囲1.6V ~ 3.6V(2.8V供給)
電流 – 供給600µA

サンプルスケッチ(GitHub)

#include <M5StickC.h>
#include <driver/i2s.h>

#define PIN_CLK  0
#define PIN_DATA 34
#define READ_LEN (2 * 256)
uint8_t BUFFER[READ_LEN] = {0};

uint16_t oldy[160];
int16_t *adcBuffer = NULL;

void i2sInit()
{
   i2s_config_t i2s_config = {
    .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM),
    .sample_rate =  44100,
    .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // is fixed at 12bit, stereo, MSB
    .channel_format = I2S_CHANNEL_FMT_ALL_RIGHT,
    .communication_format = I2S_COMM_FORMAT_I2S,
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
    .dma_buf_count = 2,
    .dma_buf_len = 128,
   };

   i2s_pin_config_t pin_config;
   pin_config.bck_io_num   = I2S_PIN_NO_CHANGE;
   pin_config.ws_io_num    = PIN_CLK;
   pin_config.data_out_num = I2S_PIN_NO_CHANGE;
   pin_config.data_in_num  = PIN_DATA;
  
   
   i2s_driver_install(I2S_NUM_0, &amp;i2s_config, 0, NULL);
   i2s_set_pin(I2S_NUM_0, &amp;pin_config);
   i2s_set_clk(I2S_NUM_0, 44100, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO);
}



void mic_record_task (void* arg)
{   
  size_t bytesread;
  while(1){
    i2s_read(I2S_NUM_0,(char*) BUFFER, READ_LEN, &amp;bytesread, (100 / portTICK_RATE_MS));
    adcBuffer = (int16_t *)BUFFER;
    showSignal();
    vTaskDelay(100 / portTICK_RATE_MS);
  }
}

void setup() {
  M5.begin();
  M5.Lcd.setRotation(3);
  M5.Lcd.fillScreen(WHITE);
  M5.Lcd.setTextColor(BLACK, WHITE);
  M5.Lcd.println("mic test");

  i2sInit();
  xTaskCreate(mic_record_task, "mic_record_task", 2048, NULL, 1, NULL);
}


void showSignal(){
  // Offset
  int32_t offset_sum = 0;
  for (int n = 0; n < 160; n++) {
    offset_sum += (int16_t)adcBuffer[n];
  }
  int offset_val = -( offset_sum / 160 );

  // Auto Gain
  int max_val = 200;
  for (int n = 0; n < 160; n++) {
    int16_t val = (int16_t)adcBuffer[n] + offset_val;
    if ( max_val < abs(val) ) {
      max_val = abs(val);
    }
  }
  
  int y;
  for (int n = 0; n < 160; n++){
    y = adcBuffer[n] + offset_val;
    y = map(y, -max_val, max_val, 10, 70);
    M5.Lcd.drawPixel(n, oldy[n],WHITE);
    M5.Lcd.drawPixel(n,y,BLACK);
    oldy[n] = y;
  }
}

void loop() {
  printf("loop cycling\n");
  vTaskDelay(1000 / portTICK_RATE_MS); // otherwise the main task wastes half of the cpu cycles
}

オフィシャルのGitHubにある最新版のサンプルスケッチを参考にしています。0.1.0のサンプルスケッチはデータがuintだったりといろいろおかしいので、修正されたものになります。

私の手元の2台を動かしたところ、無音でも-1500前後数値でしたので、表示部分のデータ平均を取得して、そこを中央に表示するオフセットを行っています。

また、かなり大きな音がしないとグラフがでないので、最大値と最小値を計算して、グラフが拡大するようにしています。

検証

検証にはefuさんの多機能 高精度 テスト信号発生ソフトWaveGeneを利用させていただきました。

上記のように1000Hzのサイン波をパソコンから再生し、イヤホンを使ってM5StickCのマイク入力を行いました。

結果、上記のようにサイン波を画面に表示することができました。再生周波数を変更することで、画面上の表示も変化しています。

まとめ

サンプルスケッチを動かすところまではできましたが、細かい詳細までは検証できていません。

また、このサンプルは100msのスリープを入れているので秒間10回しか描画しません。そして1度に受け取っているデータが256個のため、全44,100サンプリング中2,560サンプリングしか受信できていないことになります。

256個受け取ったデータも、画面上には横160個分しか表示していないので、96サンプリングは捨てています。なんとなく波形を表示させたり、FFTで周波数分析をする分には問題ありませんが、ちゃんと利用するためにはかなり手をいれないとダメな気がします。

ESP32の選び方 2019年9月

ESP32の選び方をまとめてみました。

ESP32

純粋なESP32はフラッシュなどを内蔵していない部品であり、無線のアンテナもないので日本ではお金をかけて技適を取得しないと利用できません。

日本国内で利用する場合には技適マークのついている商品を利用する必要があるので、気をつけて選びましょう。

ESP32-WROOM-32

技適取得済みのパッケージ版です。左側が単品で、右側がブレイクアウトして使いやすくしたものです。自分で基板を作成する場合にはよいのですが、通常用途では使いにくいためおすすめしません。

初期には開発ボードがなかったので、単品を使っていた事例が多かったですが、現状はいろいろ回路を追加しないと動かないのでおすすめしません。

ESP32開発ボード

ESP32-WROOM-32に動作に必要な回路やUSB接続を追加した開発ボードです。左2つは同じように見えますが、ピンの数が違います。

機能的にはほぼ同じようなものですが、ボードの大きさが何種類かあります。一番左が片側15ピンの30ピンモデル。左から2個目は片側19ピンの38ピンモデル。また横幅も狭いものや広いものがあります。

個人的には小さい30ピンモデルが使いやすいのでよく使っていますが、ピンが少ないので使いたくても使えないピンがあります。

私がよく使っているのが、上のブレッドボードですが、縦17ピンしかありません。そのため小さいサイズの開発ボードしか使うことができません。

また、横幅が広いと普通の片側5列のブレッドボードを使うと、片側1列しか利用することができません。

上記のサンハヤトの片側6列あるブレッドボードか、左右の耳が取れるブレッドボードを連結して使うと便利だと思います。

上記がESP32の開発元が販売しているリファレンス機となります。これが一番サイズが大きいですが、安定動作するはずです。

日本国内に限っては上記ボードが、利用者が多いようです。

M5StickC

いまは、商品をメインで使っています。液晶画面と小さいバッテリー、赤いLEDライトと赤外線送信に2つのボタンと電源ボタンを内蔵しています。

通常用途であれば十分利用できるのですが、小さい分使えるピンが少ないです。実際のところそんなにピンを使う用途って無いので、80%ぐらいの用途はこれでカバーできる気もします。

また、現在は製造が追いついておらず、商品が品薄です。

上記が正規取扱い店です。Amazonだとまだ品薄なので、中国からの並行輸入品が販売されています。M5Stack Official Storeが安いのですが、海外発送なので1週間から2週間程度届くまでに時間がかかります。

本体と合体することで拡張できるHATや、ケーブルで接続することで使えるUNITもありますので機能拡張も可能です。

M5Stack

M5StackはM5StickCより大きく、種類もたくさんあります。BASIC、GRAY、FIRE、GOがありますが、まず1台であれば加速度センサーがついていて、標準的なGRAYがおすすめだと思います。

上記動画で選び方が解説されていますので、参考にしてください。機能拡張はM5StickCと同じケーブルで接続するUNITの他に、積み重ねて使うModuleがあります。

その他の開発ボード

いろいろありますが、商品的にあまり安定供給されていないイメージがありますのでおすすめしません。

カメラが利用したい場合には、以下の選択肢もあります。

Arduino以外のOS搭載ボード

obnizはJavaScriptで開発できるボードです。最近OSだけも販売をはじめましたので、通常のESP32開発ボードにOSを入れて使うこともできます。Nefry BTはArduino IDEで開発することができますが、ブラウザを利用した管理画面などがあります。

その他PythonやJavaScriptで開発ができるOSもありますので、通常のESP32開発ボードにいれて使うことも可能です。

まとめ

Espressif社のESP32-DevKitCがリファレンス機ですが、あまり流通していないのでこれという標準機が存在していません。

画面がついていて、箱にはいっているM5Stack社の製品が人気です。ただ海外製品が多いので、使っている部品が途中から変わって、バージョンアップしていることがありますので注意してください。

Arduinoのはじめ方 2019年9月

いまからArduinoをはじめる方法を紹介します。

[無料] Autodesk Tinkercad

AutodeskはAutoCADという有名なCADソフトを作っている老舗企業です。主に学生向けにArduinoなどのプログラミングや、3Dデザインをブラウザ上で学習することができます。

Arduinoもブラウザ上でコードをいれて、実行をすると動きをシミュレートしてくれます。無料で使えるので、ちょっとどんな感じかなと試してみるのに適していますが、中身が英語で部分的にしか日本語化していないのがネックです。

また、登録しないと利用できないので、ちょっと不便ですね。機能的にはかなり充実していますが、このサイトだけだとチュートリアル的なものが足りないので教材は別に準備したほうがいいと思います。

ELEGOO Arduino用スターターキット レベルアップ

私が最初に買った学習用のキットですが、Arduino UNO互換機の他に学習で利用する部品が含まれています。とりあえず持っていたほうが便利な部品が一式含まれているのと、日本語でのドキュメントが充実しています。

ドキュメント自体はCDで付属していますが、サイトからダウンロードも可能です。このドキュメントはよくできているので、これをダウンロードして、Autodesk Tinkercad上で無料でためしてみるのもいいかもしれません。

予算があるのであれば、実物を動かしながら学習したほうが理解は早いと思います。LEDとかを実際に利用してみて、抵抗を入れ忘れて壊すみたいな体験をしたほうが記憶には残りやすい気がします。

より部品数が多いキットや、スマートカーが入っているキットもあります。どんなことができるかは事前にドキュメントをダウンロードして見比べることもできます。

ELEGOO以外にも似たようなセットがありますが、ドキュメントはELEGOOが一番充実していると思います。

もしくは、書籍とその中で利用している部品のセットもあります。こちらの方が初学者向けの内容ではあります。実際の書籍がほしい場合にはこのセットがおすすめです。

ESP32

Arduino UNOは非常に使いやすく、標準的なボードですが無線通信ができません。そのため無線を内蔵しているESP32もおすすめします。最初の一台はUNOと部品セットの方が使いやすいと思いますが、2台目には通信ができるESP32がいいと思います。

ただ外付けの部品を使わないとか、完成品のユニットを接続しかしないのであれば、1台目からESP32のケース付きのボードが使いやすいです。

たとえば、M5StackかM5StickCなどの液晶画面とバッテリー付きESP32の商品に、上記のような温度センサーや、人感センサー、ボタンなどを組み合わせて使う場合には、箱付きの商品を最初から使ったほうが簡単です。

まとめ

単価でいうと部品を自分で組み合わせた方が安いですが、ケースなどを揃えると高くなってしまいます。自分専用のセットで部品を壊しながら学ぶのであればUNOのセット。複数人で簡単にできる学習用であれば箱入りの商品が無難です。

おすすめは、Arduino UNOのセットを購入し、その後にプレーンなESP32で無線を使ってみて、最後にM5StackかM5StickCなどの箱付き製品を使うのが、どっぷり楽しめます。

電子工作は動いている分には問題ないのですが、動かない場合の問題切り分けに追加機材が必要になったりします。ESP32の箱付き商品で問題が出た場合、プレーンなESP32でも同じ問題がでるかを確認したり、UNOで動作検証をしたりと複数持っていたほうが嬉しい場合も多いです。

M5StickCで赤外線リモコンを使う

本体に内蔵している赤外線ユニットを利用してNECフォーマットの赤外線送信を実験しました。現時点の情報ですので最新情報はM5StickC非公式日本語リファレンスを確認してください。

概要

M5StickCにはGPIO9に赤外線リモコン用のIRが内蔵されており、汎用的なリモコンとして利用が可能です。

ローレベルな関数を利用して、直接送信することも可能ですが、一般的な利用を想定して外部ライブラリを利用しています。

利用ライブラリ(IRremoteESP8266)

IRremoteESP8266はArduinoの標準ライブラリからインポートして利用することができるライブラリで、IRremoteという有名な赤外線リモコンのライブラリをESP8266とESP32に特化した形でフォークしたものです。

元になったIRremoteは受信しかできませんが、IRremoteESP8266を利用することで送信も可能です。

受信テスト

送信できたのかを確認するためには、受信環境を用意したほうがテスト簡単です。テレビとそのリモコンがあれば、送信コードを調べることで最低限確認ができますが、前回利用した赤外線受信ユニットを利用して実験を行いました。

まずは、本物のリモコンを操作して、どんなコードが飛んでいるのかを確認して、そのコードと同じものを送信できるようにします。

受信側はIRremoteESP8266のサンプルスケッチであるIRrecvDumpV2を利用すると簡単に分析が可能です。受信ユニットを接続したPINの番号を変更するだけで動きました。もちろん前回実験したときと同じデータが受信できました。

送信側コード(GitHub)

#include <M5StickC.h>
#include <IRremoteESP8266.h>
#include <IRsend.h>
#include <IRutils.h>

const uint16_t kIrLed = 9;              // M5StickCはGPIO9にIRが内蔵

IRsend irsend(kIrLed);                  // IR送信を宣言

const uint32_t CUSTOMER_CODE = 0x00ff;  // カスタマーコードをセット

// リモコンコード保存用構造体
struct REMOTE {
  char name[9];
  uint8_t command;
};

// リモコンコード一覧
REMOTE remote[] = {
  { "POWER" , 0x45 },
  { "VOL+"  , 0x46 },
  { "VOL-"  , 0x15 },
  { "0"     , 0x16 },
  { "1"     , 0x0c },
  { "2"     , 0x18 },
  { "3"     , 0x5e },
  { "4"     , 0x08 },
  { "5"     , 0x1c },
  { "6"     , 0x5a },
  { "7"     , 0x42 },
  { "8"     , 0x52 },
  { "9"     , 0x4a },
};

int cursor = 0; // カーソル位置

void setup() {
  M5.begin();     // M5StickC初期化
  irsend.begin(); // IR初期化

  // リモコン項目表示
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setCursor(0, 8);
  for ( int i = 0 ; i < ( sizeof(remote) / sizeof(REMOTE) ) ; i++ ) {
    M5.Lcd.print((cursor == i) ? ">" : " ");
    M5.Lcd.println(remote[i].name);
  }
}

void loop() {
  M5.update();  // ボタン状態更新

  // M5ボタンで送信
  if ( M5.BtnA.wasPressed() ) {
    // 送信4Byte(カスタマーコード2Byte+リモコンコード+反転リモコンコード)
    uint64_t send = 0;
    send = (uint64_t)reverseBits(CUSTOMER_CODE >> 8, 8) << 24;    // カスタマーコード(上位8bit)
    send += (uint64_t)reverseBits(CUSTOMER_CODE &amp; 0xff, 8) << 16; // カスタマーコード(下位8bit)
    send += reverseBits(remote[cursor].command, 8) << 8;          // リモコンコードを順番入れ替えて送信
    send += reverseBits(remote[cursor].command, 8) ^ 0xff;        // リモコンコードのビット反転(パリティ)
    irsend.sendNEC(send);                                         // 送信

    // デバッグ表示
    Serial.printf("Send IR : 0x%08LX", send);
    Serial.printf("(customer=0x%04X, ", CUSTOMER_CODE);
    Serial.printf("command=0x%02X)\n", remote[cursor].command);
  }

  // 右ボタンでカーソル移動
  if ( M5.BtnB.wasPressed() ) {
    cursor++;
    cursor = cursor % ( sizeof(remote) / sizeof(REMOTE) );

    // カーソル描画
    M5.Lcd.setCursor(0, 8);
    for ( int i = 0 ; i < ( sizeof(remote) / sizeof(REMOTE) ) ; i++ ) {
      M5.Lcd.println((cursor == i) ? ">" : " ");
    }
  }

  delay(100);
}

上記を実行するとリモコンの一覧がでてきて、右ボタン(Bボタン)でカーソルが動き、下ボタン(Aボタン)で送信をします。

IRremoteESP8266のサンプルスケッチであるIRsendDemoのPINを9に変更してまずは動かしたほうがわかりやすいと思いますが、PIN番号を指定して宣言すればあとは実際に送信するコードを指定するだけで動きます。

赤外線リモコンのコードは会社によって複数フォーマットがあり、今回は一番有名なNECフォーマットで送信しています。

NECフォーマットの特徴としては2バイトのカスタマーコード(会社)があり、ここで自分が利用するコード以外が来たら無視する設定になっています。その後に送信するリモコンコードと、そのコードを反転したパリティの4バイトを送るのですが、ビットの並びが下位から上位の順番なのでreverseBits()関数を利用して順番を入れ替えています。

Send IR : 0x00FFA25D(customer=0x00FF, command=0x45)

上記が0x45(POWERボタン)のコードを送ったときのデータですが、ビットの並びが違うので、実際に送信されたデータを見ただけだとすぐに解析ができません。

実際に利用する場合には、実物のリモコンが送信している0x00FFA25DをPOWERボタンとしてデータ保持しているほうがシンプルなコードになります。

シンプル送信側コード(GitHub)

#include <M5StickC.h>
#include <IRremoteESP8266.h>
#include <IRsend.h>

const uint16_t kIrLed = 9;              // M5StickCはGPIO9にIRが内蔵

IRsend irsend(kIrLed);                  // IR送信を宣言

// リモコンコード保存用構造体
struct REMOTE {
  char name[9];
  uint64_t command;
};

// リモコンコード一覧
REMOTE remote[] = {
  { "POWER" , 0x00FFA25DUL },
  { "VOL+"  , 0x00FF629DUL },
  { "VOL-"  , 0x00FFA857UL },
  { "0"     , 0x00FF6897UL },
  { "1"     , 0x00FF30CFUL },
  { "2"     , 0x00FF18E7UL },
  { "3"     , 0x00FF7A85UL },
  { "4"     , 0x00FF10EFUL },
  { "5"     , 0x00FF38C7UL },
  { "6"     , 0x00FF5AA5UL },
  { "7"     , 0x00FF42BDUL },
  { "8"     , 0x00FF4AB5UL },
  { "9"     , 0x00FF52ADUL },
};

int cursor = 0; // カーソル位置

void setup() {
  M5.begin();     // M5StickC初期化
  irsend.begin(); // IR初期化

  // リモコン項目表示
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setCursor(0, 8);
  for ( int i = 0 ; i < ( sizeof(remote) / sizeof(REMOTE) ) ; i++ ) {
    M5.Lcd.print((cursor == i) ? ">" : " ");
    M5.Lcd.println(remote[i].name);
  }
}

void loop() {
  M5.update();  // ボタン状態更新

  // M5ボタンで送信
  if ( M5.BtnA.wasPressed() ) {
    // 送信4Byte(カスタマーコード2Byte+リモコンコード+反転リモコンコード)
    irsend.sendNEC(remote[cursor].command);

    // デバッグ表示
    Serial.printf("Send IR : 0x%08LX", remote[cursor].command);
  }

  // 右ボタンでカーソル移動
  if ( M5.BtnB.wasPressed() ) {
    cursor++;
    cursor = cursor % ( sizeof(remote) / sizeof(REMOTE) );

    // カーソル描画
    M5.Lcd.setCursor(0, 8);
    for ( int i = 0 ; i < ( sizeof(remote) / sizeof(REMOTE) ) ; i++ ) {
      M5.Lcd.println((cursor == i) ? ">" : " ");
    }
  }

  delay(100);
}

実物のリモコンが手元にある場合には、受信して確認したデータをそのまま送信したほうが楽だと思います。ネット上で送信データを調べた場合には内部的な数値なのか、送信時のデータなのかを確認してから利用してください。

まとめ

赤外線リモコンは、データ送信時にビット配列を入れ替えるところがちょっと面倒です。またM5StickCのリモコンデータは受信側の性能とあると思いますが、2メートルぐらいの範囲ぐらいまで安定して送信できました。

ただし、実験で利用したELEGOOのリモコンもほぼ同じ距離だったので、安いリモコンはこれぐらいの距離が限界なのかもしれません。

M5StickCのAXP192で外部電源を使う

まだまだ謎の多いAXP192ですが、ちょっとだけわかってきました。現時点の情報なので最新情報はM5StickC非公式日本語リファレンスを確認してください。

概要

M5StickCには外部電源用に5V INの端子があります。しかしながらAXP192のデータシート上は2.9Vから6.3Vまでの入力を許容しています。

また、3.8V以上の入力があると自動起動をするようです。

外部電源の実験

2台のM5StickCを利用して、GNDを共有してから、片方のBAT端子からもう片方の5V INに接続してみました。安定化電源が壊れたので簡易測定です。

BAT側のM5StickCが4V以上の場合

5V IN側のM5StickCが充電されながら動いていました。

BAT側のM5StickCが3.7V前後の場合

5V IN側のM5StickCで充電はされなくなりましたが、外部電源で動いていました。

BAT側のM5StickCが3.5V前後の場合

この辺から外部電源を使わなくなりました。

外部電源との電源連動(GitHub)

#include <M5StickC.h>

// 最後に電圧確認した時間
int lastVinTime = 0;

// AXPを電源オフする
void axp_halt(){
    Wire1.beginTransmission(0x34);
    Wire1.write(0x32);
    Wire1.endTransmission();
    Wire1.requestFrom(0x34, 1);
    uint8_t buf = Wire1.read();

    Wire1.beginTransmission(0x34);
    Wire1.write(0x32);
    Wire1.write(buf | 0x80); // halt bit
    Wire1.endTransmission();
}

void setup() {
  M5.begin();
  M5.Lcd.fillScreen(WHITE);
}

void loop() {
  if( (M5.Axp.GetVinData()*1.7) < 3.0 ){
    if( lastVinTime + 5000 < millis() ){
      // 3.0V以下が5秒以上で電源オフ
      axp_halt();
    }
  } else {
    // 最終電圧確認時間更新
    lastVinTime = millis();
  }

  delay(500);
}

外部電源からの入力をM5.Axp.GetVinData()で監視して、一定以下の電圧が指定秒数以上続くと電源を落とすサンプルです。

電源オフは本家ライブラリにプルリクエストを出しているので、そのうち取り込まれる可能性がありますが、現時点では自作する必要があります。

電源オンは5V INに3.7V以上の電源を接続したときに自動起動します。このため5Vで動作する回路とM5StickCを連携させ、外部電源がなくなったらプログラムで電源オフにして、回路から5Vが供給すると電源オンになる連携が可能になります。

まとめ

AXP192のデータシート上2.9Vからの動作になっていましたが、安定動作させるには3.5V以上の電圧が必要でした。この電圧だと18650などのリチウムイオン充電池の直結は厳しいかな?

M5StickCの内蔵電池はかなり容量が小さいので、18650や16340であれば直結でも動きそうですが、安定動作にはやっぱり5Vに昇圧したほうが良さそうでした。

安定化電源が壊れて使えなかったので、ちょっと機材購入して追加で調査したいと思います。

M5StickCのAXP192の電源周りを調べる

入力と出力まわりを中心にAXP192を調べ直しました。現時点の情報ですので最新情報はM5StickC非公式日本語リファレンスを確認してください。

概要

ざっくりと電源周りをまとめてみました。5V出力がちょっと複雑ですが、あとは概ね想定内でした。M5StickC以外にもAXP192は利用されそうですので、全般的な説明も追加しています。

入出力一覧

PIOAXP NAME接続先電圧電圧範囲最大電流備考
入力VBUSUSB 5V IN5V
入力ACIN5V IN5V
出力DCDC1ESP32, 3V33.3V0.7V〜3.5V1.2A
出力DCDC2未使用0.7V〜2.275V1.6A
出力DCDC3未使用0.7V〜3.5V0.7A
出力LDO1RTC3.3V1.25V〜3.3V30mA常時給電
出力LDO2TFT3.0V1.8V〜3.3V200mA低ノイズ
出力LDO3LCD3.0V1.8V〜3.3V200mA低ノイズ
出力GPIO0/LDOio0MIC2.8V1.8V〜3.3V50mA低ノイズ
出力IPSOUT5V OUT5V or BAT

入力はUSBからのVBUSと、5V入力のACINが別系統であります。両方接続しているときには、ACINが優先されます。

出力はDCDCが3系統、LDOが4系統あります。

電力入力端子

VBUSとACINは両方接続されていても問題ありません。その場合にはACINが優先されて利用されます。

VBUS(USB)

USBからの電源供給です。VBUSは電流制限(0x30)が可能でM5StickCでは500mAまでの制限が入っています。3.8V以上の電源が入力されるとAXP192は自動起動します。

ACIN(5V IN)

上部のHAT端子の5V INからの電源供給です。3.8V以上の電源が入力されるとAXP192は自動起動します。

電力出力端子

DCDC1(ESP32, 3V3)

ESP32と3V3出力端子に電源を出力します。電源ONの場合にしか出力されません。AXP192をスリープした場合でも出力され続けます。

DCDC2, 3

M5StickCでは利用していません。

LDO1(RTC)

RTCに接続されており、時刻を保存するために利用されています。電源OFFになっていても出力されています。おそらく接続的にはRTCのバッテリーを3.0Vまで充電するという動きをしているはずです。

LDO2(TFT)

画面の明るさ制御に利用している電源です。電源OFFの場合や、AXP192をスリープすると出力されません。

LDO3(LCD)

おそらくTFTの制御ボードであるST7735Sが利用している電源です。電源OFFの場合や、AXP192をスリープすると出力されません。

GPIO0/LDOio0(MIC)

汎用的に利用できるGPIOですが、M5StickCは低ノイズの電源出力で利用しています。MICで利用しているSPM1423が接続されているはずです。

IPSOUT

ここの出力はAXP192というよりは、利用するボードによって異なってくるはずです。基本的には5Vが出力されていますが、バッテリー電圧が出力される場合があります。

出力の優先順位は以下の通りです。

  • ACIN(5V IN)
  • VBUS(USB)
  • (AXP192電源ON)バッテリーのAXP192経由のDCDC 5V
  • (AXP192電源OFF)バッテリー電圧

外部電源が接続されていない場合でも、AXP192が電源ONであればDCDCを利用して5Vが出力されていますが、AXP192ではない外部DCDCを利用しているように思えます。

そのためAXP192が電源OFFの場合にはバッテリー電圧が出力されるので、3Vから4V程度の電圧出力になっている可能性があります。

BAT

バッテリー電圧を出力する端子があります。この端子は常時出力されています。おそらくAXP192経由で過放電は禁止されているはずですが、未検証です。

まとめ

内部の結線図はGitHubのissues「RTC interrupt pin connected to ESP32 or not? #45」にあるので、参考にしました。

GPIO35に関しては、IRQはプルアップが必要なんですが、回路上プルアップしていないのと、GPIO35の内蔵プルアップもできないので、実質利用できない気がします。

また、MIC利用しない場合には、電源OFFしたほうが省電力になる可能性がありますが、手持ちの機材だと数十mA単位しか測定できないので、もう少し高精度に測定できる機材調達中です。

M5StickCの端子別動作確認

外部接続可能な端子について、状況別の確認をしてみました。現時点の情報です、最新情報はM5StickC非公式日本語リファレンスで確認してください。

概要

Arduino UNOに接続可能な端子をつないでみて、出力値を確認してみました。

条件GPIO0GPIO26GPIO36GPIO32GPIO33BAT3V35VGrove5V
電源オフONOFFONON
電源オン 初期化無しHIGHONONONON
M5.begin();HIGHONONONON
INPUT初期化のみHIGHONONONON
INPUT_PULLUP初期化のみHIGHHIGHHIGHHIGHONONONON
INPUT_PULLDOWN初期化のみHIGHLOWLOWLOWONONONON
ANALOG初期化のみHIGHONONONON
OUTPUT初期化のみLOW※LOWLOWLOWONONONON
OUTPUT LOWLOW※LOWLOWLOWONONONON
OUTPUT HIGHHIGHHIGHHIGHHIGHONONONON
OUTPUT_OPEN_DRAIN初期化のみLOW※LOWLOWLOWONONONON
OUTPUT_OPEN_DRAIN LOWLOW※LOWLOWLOWONONONON
OUTPUT_OPEN_DRAIN HIGHHIGHONONONON
ESP32 Timer DeepSleepHIGHONONONON
ESP32 Timer LightSleepHIGHONONONON
AXP192 SleepHIGHHIGHHIGHHIGHONONONON

BAT端子

内蔵バッテリーの出力端子で、 3Vから4V程度が常に出力されています。

3V3

3.3Vが出力される端子で、この端子のみ電源OFFだと出力されません。

5V

5Vが出力される端子で、常に出力されています。

GROVE 5V

Grove端子側の5V端子で、常に出力されています。ただ、GPIO32とGPIO33の入力は3.3Vまでなので、接続する装置によってはこの電源の5Vの入力がそのまま入る可能性があります。とはいえ、実際のところ5Vの入力を入れても壊れることはないようですが、正式には5V入力を許容していませんので注意して利用してください。

GPIO0

基本的に3.3Vでプルアップされている端子で、電源オフ時とLOWの出力時以外はHIGHになっています。ただLOWのときにもGNDレベルではなく150mV程度の電圧が出力されていました。

また、この端子をLOWに落としている時は、起動に失敗しますので接続には注意してください。

GPIO26

非常にシンプルな端子で、素直に動きます。また、M5StickCではDAC出力に唯一使える端子でもあります。

GPIO36

入力専用端子で出力はできません。また、プルアップとプルダウンも利用できませんので注意しましょう。

GPIO32, 33

Grove側の端子で、素直に動きます。Groveの電源が5Vですが、この端子の入力は3.3Vまでなので注意しましょう。

まとめ

気をつけないといけないのはGPIO0がプルアップされていることと、LOWになると起動失敗すること。そしてGPIO36がプルアップもプルダウンも使えないことです。

また、スリープをした場合、モードによりますが端子がオープンになるのは通常のESP32と一緒ですが、電源端子系はそのままなので注意が必要です。そしてAXP192のスリープはI2Cは生きたままなので、LCDだけ電源オフにしている感じに見えますが、もうちょっと調査が必要そうでした。

電子工作用ロボット部品

中国からキットでも買おうかと思っていましたが、タミヤから出ているものが一番使いやすそうです。

書籍

なんとなくみたことがあったのですが、この書籍で初めてタミヤの楽しい工作シリーズを知りました。

この書籍で紹介されているのは一部だけで、かなり古い本なのでいまはかなりシリーズが増えていると思います。

パーツ

上記のようなベースとなるプレートと、各種アープパーツで骨格を作ることができます。

ユニット

モーターはもちろん、ギヤボックや特殊な構造に便利なユニットがたくさんあります。

セット

最後のキットは知っていたのですが、ちょっと高すぎると思ってスルーしていました。安いものも結構あって、リモコン付きに物をベースにESP32などを組み込んでリモコン制御にするとか楽しそうですね。

まとめ

中国から購入するより、国内で頼んだほうが安心で同じものが購入できて便利ですね。Amazonの場合、たまに在庫がなくて高いものが混ざっていますので、ヨドバシと見比べて購入したほうがいいかもしれません。

ESP32のpinMode()について調べた

INPUT, OUTPUT, INPUT_PULLUPしかないと思っていたら、ANALOGとか他にもあったのね、、、

現時点の情報になりますので、最新情報はM5StickC非公式日本語リファレンスを確認してください。

概要

標準のArduinoとESP32ではpinMode()の設定値が違いますので注意しましょう!

利用する前に正しい設定値で設定してから使いましょう。PINによって初期値が違いますので、たまたま動いていたものを、他のPINに移動したら動かなくなったなどのトラブルになりやすいです。

モードの組み合わせ要素

入出力(INPUT, OUTPUT, ANALOG)

INPUTかOUTPUTかで入力用なのか、出力用なのかを選びます。ただしアナログ処理に関しては別途ANALOGという選択肢があります。

ANALOGを選ぶとADCの割当を行っているので、アナログ出力のDACはOUTPUTを指定するような気がしますが、実際にはANALOGでもアナログ出力が可能でした。

プル(PULLUP, PULLDOWN)

プルアップの場合には、電源から内部プルアップ抵抗を経由して、PINに接続されます。通常はHIGHで、そのPINに接続したスイッチやケーブルなどがGNDに接続されるとLOWになります。ノイズに強いことと、複数の機材が接続しているときでもGNDに落とせば誰かがシグナルを出しているのかがわかりやすいので使われています。

プルダウンの場合には、GNDに内部プルダウン抵抗を経由して、PINに接続されます。通常はLOWで、そのPINに接続したスイッチやケーブルなどが電源に接続されるとHIGHになります。こちらもノイズがのってもGNDに流れるので、ノイズの影響を受けにくくなります。

無指定の場合には、どちらでもありません。GNDや電源に接続されている場合には正しい数値になりますが、なにも接続されていない場合には電気が流れる先がないので、センサーに残っている、変な値を取得することになります。

プルダウンも、プルアップも回路上に本来不要な電気がすこし流れることになるので、電力的にはすこしロスになります。ただし、通常は気にするほどの量ではないと思います。

また、プルダウンとプルアップはどちらも同じような効果の回路ですが、一般的にはプルアップがよく使われています。過去はプルダウンを利用したほうがよいICが多かったのですが、現状は慣習としてプルアップを利用している場合が多いです。

オープンドレイン(OPEN_DRAIN)

I2Cなどで使われており、LOWは0Vになるが、HIGHは何もしない(ハイインピーダンス)の状態です。

そのPIN以外がプルアップでHIGHにしている回路に対して、LOWにしたい場合に利用します。HIGHのときに出力をしないのは、すでにプルアップされているのでHIGHの出力が意味がないからです。また、接続先がLOWになっている場合に、出力したHIGHの電力が無駄になるからです。

設定可能なモード

  • INPUT
  • OUTPUT
  • PULLUP(単独指定不可)
  • INPUT_PULLUP
  • PULLDOWN(単独指定不可)
  • INPUT_PULLDOWN
  • OPEN_DRAIN(単独指定不可)
  • OUTPUT_OPEN_DRAIN
  • SPECIAL
  • FUNCTION_1
  • FUNCTION_2
  • FUNCTION_3
  • FUNCTION_4
  • FUNCTION_5
  • FUNCTION_6
  • ANALOG

上記の中でSPECIALとFUNCTION系は特殊なモードで、UARTやSPIを初期化するときに利用するモードみたいですが、普通は使うことはないはずです。

INPUT_PULLUPは(INPUT | PULLUP)の指定になるので、実質的に利用するのは下記の6種類になります。

  • INPUT
  • INPUT_PULLUP
  • INPUT_PULLDOWN
  • OUTPUT
  • OUTPUT_OPEN_DRAIN
  • ANALOG

まとめ

実際のところ、INPUT, OUTPUT, INPUT_PULLUP, ANALOG以外は、実質利用しないみたいです。ANALOGがちゃんと取得できるようになったので良かったです。