LoginSignup
10
4

More than 3 years have passed since last update.

Wio LTEの省電力運用についての試行錯誤

Last updated at Posted at 2019-03-01

Wio LTEの消費電力を抑えるために試行錯誤した結果、
Standbyモードに入れることで10mA未満に抑えることができたので、
そこに至るまでの過程と、Standbyモードの注意点を書いておきます。

きっかけ

Wio LTEにUSB電圧チェッカーを挟んで、消費電力をチェックしてみたところ、
動作中に最大260mA消費していることが分かりました。
また、センサーをSleepさせ、次のデータ送信のタイミングまで待機させる間にも10mA〜170mA常時消費していました。
USB給電ではなく、バッテリー給電を考えていたため、これではすぐに電池が無くなってしまいます。
よく他のマイコンでは、待機中にSleepモードを利用していたため、
Wio LTEでもSleepモードといった省電力モードがあるか調べることになりました。

Wio LTEのライブラリで用意されているSleep関数を使ってみる

Wio LTEのWikiページを見たところ、Sleep関数があったので使ってみました。

sleep.ino
#include <WioLTEforArduino.h>

WioLTE Wio;

void setup() {
  Wio.Init();
  SerialUSB.println("sleep");
  Wio.Sleep();
}

void loop() {

}

上記のプログラムを実行すると、Sleep関数に入った後は電流が10mA以下〜50mAほどになります。

プロセッサーのStandbyモードを使う

もっと消費電力を抑えられる方法は無いか探していると、こんな記事を見つけました。
Wio LTEの本気を引き出す(低消費電力編)
プロセッサー(STM32F405)の低電力モードのStandbyモードを使用すると、1mA以下まで消費電力を抑えることができるそうです。
今までの数字が大きかった分「本当か!?」と疑いつつ、参考にしてやってみることにしました。
結果的には、常時10mA未満にまで電流を抑えることができました!
しかし、ここで結構長い時間はまりました……

西暦を下2桁しか取って来なくて混乱する

上記サイトのプログラムを実行してみると、シリアルモニタにはこのような文字列が表示されます。
1919年という日付
1919年という謎の西暦が出てきました。
これは、STM32F4xxのRTClockライブラリ内のsetTime関数が原因です。
setTime関数は、1900年1月1日0時0分0秒から今日に至るまでに経過したtime_t型の秒数を、
日付の形式である構造体tm型に直してプロセッサーに時刻を設定する関数です。
しかし、RTClock.cppのsetTime関数の中身をよく見てみると……
RTClockcpp.png
何故かyearを100で割ってしまうため、西暦を下2桁しか保持できません。
現在が2019年なので、2019 - 1900 = 119という数字をyearは持っているのですが、
この関数によって下2桁のみ(=19)というデータになってしまい、
1900 + 19 = 1919年という奇妙な西暦が生まれてしまうのです。
更に、曜日wdayも、西暦に影響されてズレが生じ、1919年の当時の曜日が算出されてしまいます。

ひたすら過去の時間に復帰しようとするため、RTCのアラーム機能を使って復帰する方法は私は諦めてしまいました。
「こうしたらできたよ!」という方法があれば、後学のために教えていただけると幸いです。

main関数内に復帰するわけではない

RTClockライブラリに記載してある、setPeriodicWakeup関数で、
待機時間の秒数を指定するようにしました。
先のサイトのStandbyモード部分のコードを抜き出して少し手を加えただけですが、
一応載せておきます。

standby.ino
#include <WioLTEforArduino.h>
#include <RTClock.h>
#include <stdio.h>
#include <time.h>
typedef int IRQn_Type;
#define __NVIC_PRIO_BITS          4
#define __Vendor_SysTickConfig    1
#include <libmaple/libmaple_types.h>
#include <libmaple/usbF4/VCP/core_cm4.h>
#include <libmaple/usbF4/VCP/core_cmInstr.h>
#include <libmaple/pwr.h>
#include <libmaple/bkp.h>

WioLTE Wio;
static RTClock rtc(RTCSEL_LSI);

void setup() {
  // put your setup code here, to run once:
  Wio.Init();
}

void loop() {
  // Standbyモードに入っているか確認
  if (PWR_BASE->CSR & (1UL << PWR_CSR_SBF)) {
    PWR_BASE->CSR |= (1UL << PWR_CR_CSBF);
  }

  SerialUSB.println("standby");
  enterStandbyMode(60); // 60秒後に復帰する
}

void clearWUF(){
  // WakeUp Flagビットをクリア
  PWR_BASE->CR |= (1UL << PWR_CR_CWUF); 
}

// Standbyモードへ移行
void setBitStandbyMode() {
  delay(1000UL);

  // PDDS(Power-Down DeepSleep)ビットをセット
  PWR_BASE->CR |= (1UL << PWR_CR_PDDS);

  // WakeUp Flagビットをクリア
  clearWUF();

  // WakeUp Flagビットがクリアされるまで待つ
  while(PWR_BASE->CSR & (1UL << PWR_CSR_WUF)) {
  }

  // Cortex-M4にSLEEPDEEPビットマスクをかける
  SCB->SCR |= (SCB_SCR_SLEEPDEEP_Msk);

  // 割り込み待ち(Standbyモード)
  __WFI();
}

void enterStandbyMode(uint16 sleep_sec){
  rtc.setPeriodicWakeup(sleep_sec); // 待機時間(秒数)をセット

  clearWUF();

  setBitStandbyMode();  // Standbyモードに入る
}

しかし、ここでまた問題が発生します。
いつまで経っても、シリアルモニタに復帰後のメッセージが表示されないのです。
しかし、しばらくするとUSB電圧計の電流の値が変化していることに気付きます。
もしや?と思い、setup関数を実行している間にLEDを点けるようにしてみました。
すると、指定した待機時間を経過した後、LEDが光り始めました。

プロセッサーから直接弄った結果、復帰の経路がmain関数内ではなく、
setup関数からやり直す=再起動をする形になりました。

まとめ

かなり長時間データシートと向き合っていましたが、プロセッサーの扱い方を理解する良い機会だったと思います。
新しいデバイスは参考資料も少ないため、既存の資料を大切に読み込むことが大切だと実感しました。

10
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
4