今回はとある案件でSleepのウォッチドッグタイマを使用した場合と
使用しなかった場合の消費電力を調査する必要があったため
その記録をここに記載しておきます。
ハードウェア構成
ソフトウェア
ウォッチドッグタイマを使用しないコード
#include <avr/sleep.h> // スリープライブラリ #include <avr/wdt.h> // ウォッチドッグタイマー ライブラリ
const int led = 8; // LEDピン
const int PUSH_PIN = 2; // 外部入力割込みピン
void setup() {
//pin set
pinMode(led, OUTPUT);
pinMode(PUSH_PIN, INPUT_PULLUP);
}
void loop() {
digitalWrite(led, LOW); // LED off
interrupt(); // 割り込みのスリープを設定
// 通常モードに復帰
digitalWrite(led, HIGH); // LED on
delay(1000); // 普通のdelay(比較用)
}
// 外部入力割込みによる起動処理
void wakeUp() {
//外部入力割込みの際に行いたい処理を記載
}
// 割り込みスリープ処理
void interrupt() {
Serial.flush(); // シリアルバッファが空になるまで待つ
// ADCを停止(消費電流 147→27μA)
ADCSRA &= ~(1 << ADEN);
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // パワーダウンモード指定
attachInterrupt(0, wakeUp, LOW); // Lowになった時にwakeUp関数起動
sleep_enable();
// BODを停止(消費電流 27→6.5μA)
MCUCR |= (1 << BODSE) | (1 << BODS); // MCUCRのBODSとBODSEに1をセット
MCUCR = (MCUCR & ~(1 << BODSE)) | (1 << BODS); // すぐに(4クロック以内)BODSSEを0, BODSを1に設定
asm("sleep"); // 3クロック以内にスリープに入る sleep_mode();では間に合わなかった
sleep_disable(); // 割り込みででここから動作再開
ADCSRA |= (1 << ADEN); // ADCの電源をON(BODはハードウエアで自動再開される)
detachInterrupt(0); //外部割込み停止
}
結果
ウォッチドッグタイマを使用したコード
#include <avr/sleep.h> // スリープライブラリ #include <avr/wdt.h> // ウォッチドッグタイマー ライブラリ
const int led = 8; // LEDピン
const int PUSH_PIN = 2; // 外部入力割込みピン
void setup() {
//pin set
pinMode(led, OUTPUT);
pinMode(PUSH_PIN, INPUT_PULLUP);
}
void loop() {
digitalWrite(led, LOW); // LED off
interruptWDT(9,true); // 割り込みのスリープを設定
// 通常モードに復帰
digitalWrite(led, HIGH); // LED on
delay(1000); // 普通のdelay(比較用)
}
// 外部入力割込みによる起動処理
void wakeUp() {
//外部入力割込みの際に行いたい処理を記載
}
// WDTがタイムアップした時に実行される処理
ISR(WDT_vect) {
//ウォッチドッグの際に行いたい処理を記載
}
// 割り込みスリープ処理
void interruptWDT(unsigned long t, bool flag) {
Serial.flush(); // シリアルバッファが空になるまで待つ
if (flag == true) {
delayWDT_setup(t); // ウォッチドッグタイマー割り込み条件設定
}
// ADCを停止(消費電流 147→27μA)
ADCSRA &= ~(1 << ADEN);
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // パワーダウンモード指定
attachInterrupt(0, wakeUp, LOW); // Lowになった時にwakeUp関数起動
sleep_enable();
// BODを停止(消費電流 27→6.5μA)
MCUCR |= (1 << BODSE) | (1 << BODS); // MCUCRのBODSとBODSEに1をセット
MCUCR = (MCUCR & ~(1 << BODSE)) | (1 << BODS); // すぐに(4クロック以内)BODSSEを0, BODSを1に設定
asm("sleep"); // 3クロック以内にスリープに入る sleep_mode();では間に合わなかった
sleep_disable(); // 割り込みででここから動作再開
ADCSRA |= (1 << ADEN); // ADCの電源をON(BODはハードウエアで自動再開される)
detachInterrupt(0); //外部割込み停止
}
void delayWDT_setup(unsigned int ii) { // ウォッチドッグタイマーをセット。
// 引数はWDTCSRにセットするWDP0-WDP3の値。設定値と動作時間は概略下記
// 0=16ms, 1=32ms, 2=64ms, 3=128ms, 4=250ms, 5=500ms
// 6=1sec, 7=2sec, 8=4sec, 9=8sec
byte bb;
if (ii > 9) { // 変な値を排除
ii = 9;
}
bb = ii & 7; // 下位3ビットをbbに
if (ii > 7) { // 7以上(7.8,9)なら
bb |= (1 << 5); // bbの5ビット目(WDP3)を1にする
}
bb |= (1 << WDCE);
MCUSR &= ~(1 << WDRF); // MCU Status Reg. Watchdog Reset Flag ->0
// start timed sequence
WDTCSR |= (1 << WDCE) | (1 << WDE); // ウォッチドッグ変更許可(WDCEは4サイクルで自動リセット)
// set new watchdog timeout value
WDTCSR = bb; // 制御レジスタを設定
WDTCSR |= _BV(WDIE);
}
結果
総括
WDTを未使用だと0.16uAとかなりの低消費だということがわかりました。