M5StickCの消費電流 その3

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

概要

GPIO系と通信系の消費電流を測定してみました。消費電流に波があるものも、ある瞬間的な消費電流を測定しているので、かなり誤差があります。

GPIOのpinMode(接続なし)

状態消費電流(mA)増減(mA)
INPUT90.20.0
INPUT_PULLUP90.20.0
INPUT_PULLDOWN90.20.0
OUTPUT LOW90.20.0
OUTPUT HIGH90.20.0
OUTPUT_OPEN_DRAIN LOW90.20.0
OUTPUT_OPEN_DRAIN HIGH90.20.0
ANALOG90.20.0

ピンに未接続な場合には、どのpinModeでも消費電流に差はありませんでした。

GPIOのpinMode(LED接続)

状態消費電流(mA)増減(mA)
INPUT90.30.0
INPUT_PULLUP90.40.1
INPUT_PULLDOWN90.30.0
OUTPUT LOW90.30.0
OUTPUT HIGH90.90.6
OUTPUT_OPEN_DRAIN LOW90.30.0
OUTPUT_OPEN_DRAIN HIGH90.30.0
ANALOG90.30.0

LEDと抵抗を接続してあります。OUTPUT HIGHで点灯した場合に0.6mAしか流れていないので、抵抗値が高すぎですが検証で明るすぎると面倒なので、かなり暗く光るようにしています。

INPUT_PULLUPでも少しだけ電流が流れていますので、うっすらと光っていました。それ以外のモードでは消費電流に差はありませんでした。

Bluetooth Serial

状態消費電流(mA)増減(mA)
起動直後90.60.0
SerialBT.begin()95.44.8
SerialBT.disconnect()94.33.7
SerialBT.end()93.12.5

開始しただけで、実際の接続がない状況での消費電流です。begin()で受信を開始すると同時に消費電流が増えました。実際に通信をするともっと増えると思いますが、頻度によってかなり増減すると思うので、今回は計測していません。

disconnect()をしても、当初よりも電流が流れた状態のままでした。end()で少し減りましたが、まだ当初より高い電流です。

ちなみに一度end()をするとbegin()をしても通信ができません。通信系は起動時にしか確保しないメモリーなどがあるみたいです。

BLE

状態消費電流(mA)増減(mA)
起動直後90.70.0
BLEDevice::init()142.952.2
pBLEScan->start()133.242.5
Scan完了93.12.4
BLEDevice::deinit(false)91.91.2
BLEDevice::deinit(true)91.91.2

BLEは init() をした瞬間が一番電力使っていました。常に通信モジュールに電源供給しているのかもしれません。pBLEScanの間は電流が増減する波があり、Scanが終わると消費電流が安定しました。

deinit()ではメモリを開放するかのフラグがありましたが、どちらでも消費電流に違いはなく、起動直後の電流にも戻りませんでした。

Wi-Fi

状態消費電流(mA)増減(mA)
起動直後91.30.0
WIFI_OFF91.30.0
WIFI_STA142.451.1
WIFI_AP145.153.8
WIFI_AP_STA144.152.8
WiFi.begin()142.351.0
WiFi.disconnect()142.651.3

ESP32のWi-Fiは子機にあたるSTA(ステーション)と、親機にあたるAP(アクセスポイント)モードがあり、オフとその両方とも使う4種類が設定できます。

WIFI_OFF以外を選択すると、その瞬間から消費電流が跳ね上がります。STAモードで接続をしてから、切断をしても消費電流はほぼ変わりませんでした。

実際に消費電流を下げるためにはWiFi.disconnect(true)で切断する必要があるのですが、WiFi.mode(WIFI_OFF)で全体をOFFにしたほうが、かんたんで安全なきがしました。

検証スケッチ

#include <M5StickC.h>
#include "BluetoothSerial.h"
#include "BLEDevice.h"
#include <WiFi.h>

BluetoothSerial SerialBT;

#include <Preferences.h>

Preferences preferences;
char wifi_ssid[33];
char wifi_key[65];

int lcd_breath = 12;
int led = 1;
int ir = 1;
int cpu = 0;
int cpu_f[] = {240, 160, 80, 40, 20, 10};
int gpio = -1;
int gpio_f[] = {INPUT, INPUT_PULLUP, INPUT_PULLDOWN, OUTPUT, OUTPUT_OPEN_DRAIN, ANALOG };
int bts = -1;
int ble = -1;
int wifi = -1;

int mode = 0;
enum {
  MODE_LCD,   // 0
  MODE_LED,   // 1
  MODE_IR,    // 2
  MODE_BTN,   // 3
  MODE_CPU,   // 4
  MODE_GPIO,  // 5
  MODE_BTS,   // 6
  MODE_BLE,   // 7
  MODE_WIFI,  // 8

  MODE_MAX
};

// Set charge flag
void SetCharge(bool charge) {
  // get param
  Wire1.beginTransmission(0x34);
  Wire1.write(0x33);
  Wire1.endTransmission();
  Wire1.requestFrom(0x34, 1);
  uint8_t state = Wire1.read();

  // set flag
  if (charge) {
    // ON
    state = state | 0x80;
  } else {
    // OFF
    state = state &amp; 0x7f;
  }

  // set param
  Wire1.beginTransmission(0x34);
  Wire1.write(0x33);
  Wire1.write(state);
  Wire1.endTransmission();
}


void setup() {
  M5.begin();

  SetCharge(false);

  // LED
  pinMode(GPIO_NUM_10, OUTPUT);
  digitalWrite(GPIO_NUM_10, HIGH);

  // IR
  pinMode(GPIO_NUM_9, OUTPUT);
  digitalWrite(GPIO_NUM_9, HIGH);

  // LCD display
  M5.Lcd.print("Hello World");
}

void loop() {
  M5.update();

  // Mode Chenge
  if ( M5.BtnB.wasPressed() ) {
    mode++;
    mode = mode % MODE_MAX;
    Serial.printf("New Mode: %d\n", mode );
  }

  if ( mode == MODE_LCD ) {
    // LCD
    if ( M5.BtnA.wasPressed() ) {
      lcd_breath++;
      lcd_breath = lcd_breath % 13;
      M5.Axp.ScreenBreath(lcd_breath);
      Serial.printf("LCD Breath: %d\n", lcd_breath );
    }
  } else if ( mode == MODE_LED ) {
    if ( M5.BtnA.wasPressed() ) {
      led = !led;
      digitalWrite(GPIO_NUM_10, led);
      Serial.printf("LED: %d\n", led );
    }
  } else if ( mode == MODE_IR ) {
    if ( M5.BtnA.wasPressed() ) {
      ir = !ir;
      digitalWrite(GPIO_NUM_9, ir);
      Serial.printf("IR: %d\n", ir );
    }
  } else if ( mode == MODE_CPU ) {
    if ( M5.BtnA.wasPressed() ) {
      cpu++;
      cpu = cpu % ( sizeof( cpu_f ) / sizeof( int ) );
      setCpuFrequencyMhz(cpu_f[cpu]);
      Serial.printf("CPU Frequency Mhz: %d\n", cpu_f[cpu] );
    }
  } else if ( mode == MODE_GPIO ) {
    if ( M5.BtnA.wasPressed() ) {
      gpio++;
      gpio = gpio % 8;

      switch ( gpio ) {
        case 0:
          // INPUT
          pinMode( GPIO_NUM_26, INPUT );
          Serial.printf("pinMode INPUT\n");
          break;

        case 1:
          // INPUT_PULLUP
          pinMode( GPIO_NUM_26, INPUT_PULLUP );
          Serial.printf("pinMode INPUT_PULLUP\n");
          break;

        case 2:
          // INPUT_PULLDOWN
          pinMode( GPIO_NUM_26, INPUT_PULLDOWN );
          Serial.printf("pinMode INPUT_PULLDOWN\n");
          break;

        case 3:
          // OUTPUT LOW
          pinMode( GPIO_NUM_26, OUTPUT );
          digitalWrite( GPIO_NUM_26, LOW );
          Serial.printf("pinMode OUTPUT LOW\n");
          break;

        case 4:
          // OUTPUT HIGH
          pinMode( GPIO_NUM_26, OUTPUT );
          digitalWrite( GPIO_NUM_26, HIGH );
          Serial.printf("pinMode OUTPUT HIGH\n");
          break;

        case 5:
          // OUTPUT_OPEN_DRAIN LOW
          pinMode( GPIO_NUM_26, OUTPUT_OPEN_DRAIN );
          digitalWrite( GPIO_NUM_26, LOW );
          Serial.printf("pinMode OUTPUT_OPEN_DRAIN LOW\n");
          break;

        case 6:
          // OUTPUT_OPEN_DRAIN HIGH
          pinMode( GPIO_NUM_26, OUTPUT_OPEN_DRAIN );
          digitalWrite( GPIO_NUM_26, HIGH );
          Serial.printf("pinMode OUTPUT_OPEN_DRAIN HIGH\n");
          break;

        case 7:
          // ANALOG
          pinMode( GPIO_NUM_26, ANALOG );
          Serial.printf("pinMode ANALOG\n");
          break;
      }
    }
  } else if ( mode == MODE_BTS ) {
    if ( M5.BtnA.wasPressed() ) {
      bts++;
      if ( bts == 0 ) {
        SerialBT.begin("ESP32test");
        Serial.printf("SerialBT.begin()\n");
      } else if ( bts == 1 ) {
        SerialBT.disconnect();
        Serial.printf("SerialBT.disconnect()\n");
      } else if ( bts == 2 ) {
        SerialBT.end();
        Serial.printf("SerialBT.end()\n");
        bts = -1;
      }
    }
  } else if ( mode == MODE_BLE ) {
    if ( M5.BtnA.wasPressed() ) {
      ble++;
      if ( ble == 0 ) {
        Serial.printf("BLEDevice::init()\n");
        BLEDevice::init("");
      } else if ( ble == 1 ) {
        Serial.printf("pBLEScan()\n");
        BLEScan* pBLEScan = BLEDevice::getScan();
        pBLEScan->setAdvertisedDeviceCallbacks(NULL);
        pBLEScan->setInterval(1349);
        pBLEScan->setWindow(449);
        pBLEScan->setActiveScan(true);
        pBLEScan->start(5, false);
      } else if ( ble == 2 ) {
        Serial.printf("BLEDevice::deinit(false)\n");
        BLEDevice::deinit(false);
      } else if ( ble == 3 ) {
        Serial.printf("BLEDevice::deinit(true)\n");
        BLEDevice::init("");
        BLEDevice::deinit(true);
        ble = -1;
      }
    }
  } else if ( mode == MODE_WIFI ) {
    if ( M5.BtnA.wasPressed() ) {
      wifi++;
      if ( wifi == 0 ) {
        Serial.println("WIFI_OFF");
        WiFi.mode(WIFI_OFF);
      } else if ( wifi == 1 ) {
        Serial.println("WIFI_STA");
        WiFi.mode(WIFI_STA);
      } else if ( wifi == 2 ) {
        Serial.println("WIFI_AP");
        WiFi.mode(WIFI_AP);
      } else if ( wifi == 3 ) {
        Serial.println("WIFI_AP_STA");
        WiFi.mode(WIFI_AP_STA);
      } else if ( wifi == 4 ) {
        WiFi.mode(WIFI_STA);

        // Wi-Fiアクセスポイント情報取得
        preferences.begin("Wi-Fi", true);
        preferences.getString("ssid", wifi_ssid, sizeof(wifi_ssid));
        preferences.getString("key", wifi_key, sizeof(wifi_key));
        preferences.end();

        // connect to WiFi
        Serial.printf("Connecting to %s ", wifi_ssid);
        WiFi.begin(wifi_ssid, wifi_key);
        while (WiFi.status() != WL_CONNECTED) {
          delay(500);
          Serial.print(".");
        }
        Serial.println(" CONNECTED");
      } else if ( wifi == 5 ) {
        Serial.printf("WiFi.disconnect()\n");
        WiFi.disconnect();
        wifi = -1;
      }
    }
  }
}

まとめ

GPIOは実際に使うまでpinMode自体で消費電流は変わらなかった。未使用のピンについては、わざわざ設定する必要はなさそうです。

無線系は一度使うと消費電流が上がったままになりやすいので、使ったあとに再起動をするか、変数をスローメモリに保存してから、タイマー0秒でのDeepSleepでの疑似リセットで、フレッシュな状態に戻したほうがいいのかもしれません。

もう少し突っ込んだ検証は、時系列で消費電流を計測する必要があり、手持ちの機材だと精度が足りないので保留します。

I2Cの電流計だと、精度がものたりないし、電流プローブは高くて手にはいらないのでマルチメーターかなと思っています。

上記あたりが電流の精度が高いかな?

ただ、このためだけに購入するにはちょっと高いので考え中です。

コメントする

メールアドレスが公開されることはありません。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)