電源・省電力

ディープスリープ

ほぼ停止して極低消費にするマイコンの状態。

概要

ディープスリープ(Deep Sleep)は、マイクロコントローラ(MCU)においてCPUコアだけでなく、ほぼすべてのペリフェラル(周辺回路)へのクロック供給と電源供給を停止し、消費電流を数µA(マイクロアンペア)から数百nA(ナノアンペア)オーダーまで極限まで削減する動作状態である。

通常のスリープモードと比較してさらに深い省電力状態であり、RTCカウンタや特定のGPIO割り込み回路など、ごく限られた回路のみが通電状態を維持する。SRAMの内容は通常失われるため、ウェイクアップ後はシステムをリセット状態から再起動するか、RTCメモリと呼ばれる専用の保持メモリから状態を復元する必要がある。

組み込みIoT機器において、ディープスリープは「コイン電池で数年間動作するセンサー」を実現するための最重要技術の一つである。

指標アクティブスリープディープスリープ
消費電流(典型値)数mA〜数十mA数十µA〜数mA数µA〜数百nA
CPU動作フル動作停止停止
RAM保持保持保持保持しない(RTCメモリを除く)
ウェイクアップ時間µs〜msms〜数十ms
ウェイクアップソース割り込み全般RTC、GPIO、WDT(限定的)

歴史・背景

ディープスリープに相当する機能は、1980〜1990年代のバッテリー駆動機器(ポケベル、電卓、リモコン)向けMCUに黎明期から存在していた。MicrochipのPIC、Atmel(現Microchip)のAVRなどはこの時代から超低消費の「パワーダウン」モードを搭載していた。

2010年代のIoTブームとともに、ディープスリープの重要性は急激に高まった。LPWA(Low Power Wide Area)通信の普及とあいまって、「単4電池2本で10年間動作するスマートメータ」や「年1回電池交換のスマートロック」といった製品が市場に登場した。

この需要に応えるべく、Nordic SemiconductorのnRF52シリーズ(ディープスリープ消費電流:1.5µA)、Silicon LabsのEFM32シリーズ(20nA)、TIのMSP430シリーズ(0.5µA)などの超低消費電力MCUが登場し、競争が激化した。ESP32もディープスリープ時に10µA以下を達成しており、Wi-Fi・BLE搭載のIoTモジュールとして広く普及している。

技術仕様

ディープスリープ中に保持される回路

ディープスリープ中、MCUは以下の最小限の回路だけを通電状態に保つ。

保持回路役割
RTCクロックタイマーウェイクアップのための時計
RTCメモリウェイクアップ後の状態復元用(数KB〜数十KB)
パワーオンリセット(POR)回路電源電圧監視
ウェイクアップ割り込みコントローラGPIO、RTC割り込みの検知
BOD(Brown-Out Detector)電圧降下検知

ESP32でのディープスリープ実装

#include "esp_sleep.h"
#include "esp_log.h"
#include "driver/rtc_io.h"

// RTCメモリに保存する変数(ディープスリープをまたいで保持)
RTC_DATA_ATTR int boot_count = 0;
RTC_DATA_ATTR float last_temperature = 0.0f;

void setup_and_deep_sleep(void) {
    boot_count++;
    ESP_LOGI("SLEEP", "Boot count: %d", boot_count);
    ESP_LOGI("SLEEP", "Last temp: %.2f", last_temperature);
    
    // ウェイクアップ原因の確認
    esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause();
    if (wakeup_reason == ESP_SLEEP_WAKEUP_TIMER) {
        // タイマーウェイクアップ処理
        perform_sensing();
    } else if (wakeup_reason == ESP_SLEEP_WAKEUP_EXT0) {
        // GPIO0によるウェイクアップ処理
        handle_button_press();
    }
    
    // ウェイクアップソースの設定
    // タイマー: 60秒後
    esp_sleep_enable_timer_wakeup(60ULL * 1000000ULL);
    
    // 外部GPIO (GPIO0, Low Level でウェイクアップ)
    esp_sleep_enable_ext0_wakeup(GPIO_NUM_0, 0);
    
    // デジタルペリフェラルの電源を切る
    esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF);
    
    ESP_LOGI("SLEEP", "ディープスリープに移行...");
    esp_deep_sleep_start();
    // この行には到達しない(ウェイクアップは再起動)
}

void perform_sensing(void) {
    // センサー読み取りをここで実行
    last_temperature = read_temperature_sensor();
    send_data_via_mqtt(last_temperature);
}

STM32のスタンバイモード(ディープスリープ相当)

STM32では「スタンバイモード」がディープスリープに相当する。

#include "stm32l4xx_hal.h"

void enter_standby_with_rtc_wakeup(uint32_t wakeup_seconds) {
    // RTC ウェイクアップタイマーの設定
    RTC_HandleTypeDef hrtc;
    
    // ウェイクアップタイマーを設定(1秒単位)
    HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, wakeup_seconds - 1,
                                 RTC_WAKEUPCLOCK_CK_SPRE_16BITS);
    
    // スタンバイフラグのクリア
    __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);
    __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
    
    // バックアップレジスタに状態を保存
    HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, application_state);
    
    // スタンバイモードへ移行
    HAL_PWR_EnterSTANDBYMode();
    // ここには戻ってこない
}

void check_wakeup_and_restore(void) {
    RTC_HandleTypeDef hrtc;
    
    // スタンバイからの復帰か確認
    if (__HAL_PWR_GET_FLAG(PWR_FLAG_SB) != RESET) {
        // バックアップレジスタから状態を復元
        application_state = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1);
        __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);
    }
}

Nordic nRF52のSystem OFF(ディープスリープ最深部)

Nordic nRF52では「System OFF」が最も深い省電力状態(1.5µA以下)である。

#include <nrf_power.h>
#include <nrf_gpio.h>

void enter_system_off(void) {
    // GPIO ピンでのウェイクアップ設定
    nrf_gpio_cfg_sense_input(BUTTON_PIN,
                              NRF_GPIO_PIN_PULLUP,
                              NRF_GPIO_PIN_SENSE_LOW);
    
    // RTCをウェイクアップソースとして設定(別途設定が必要)
    
    // System OFF モードへ移行
    nrf_power_system_off(NRF_POWER);
    // この行には到達しない
}

動作原理

ディープスリープの動作原理は、電源ゲーティング(Power Gating)技術による。

通常動作中、MCU内部はVDDから全回路に電圧が供給される。ディープスリープモードへの移行指示を受けると、電源管理回路は以下の順序で電源を切断する。

  1. CPUコアの停止: 実行中の命令を完了し、プログラムカウンタを保存
  2. SRAMの電源切断(または保持電圧低減): RAMの内容を失う(または専用のRetention RAM のみ保持)
  3. フラッシュコントローラの停止
  4. 各ペリフェラルへのクロック・電源切断: ADC、UART、SPI、I2Cなど
  5. メインクロック(PLL)の停止: 最も電力を消費するクロック生成回路をオフ
  6. RTCドメインのみ通電維持: 低周波数(32.768kHz)のRTCクロックと最小限の回路

この状態では、MCU内部の大部分がオフになっており、消費電力のほとんどはCMOSトランジスタのリーク電流(サブスレッショルドリーク、ゲートリーク)と、RTCドメインの動的消費電力のみとなる。

RTCメモリの仕組み

ESP32のRTCメモリは、ディープスリープ中も電源が維持される特殊なSRAM領域(8KB〜16KB程度)である。RTC_DATA_ATTR 属性を付与した変数はこの領域に配置され、ディープスリープをまたいでデータを保持できる。STM32のバックアップレジスタ(20バイト〜数KB)も同様の役割を果たす。

用途・ユースケース

環境センサーIoTノード

最も典型的な用途は、温度・湿度・気圧・CO2などを定期計測してクラウドへ送信するIoTセンサーである。「10分に1回計測・送信、残り9分59秒はディープスリープ」という設計で、コイン電池(CR2032: 220mAh)でも数ヶ月〜1年以上の動作が可能になる。

アクティブ期間: 2秒(計測1秒 + BLE送信1秒)
アクティブ消費電流: 15mA(BLE送信含む)
ディープスリープ期間: 598秒
ディープスリープ消費電流: 3µA

平均消費電流 = (15mA×2 + 0.003mA×598) / 600 ≈ 0.053mA = 53µA

CR2032(220mAh)の寿命 ≈ 220 / 0.053 ≈ 4150時間 ≈ 約173日(約6ヶ月)

スマートロック・スマートキー

ドアの鍵の開閉はまれにしか発生しないため、ほぼ常時ディープスリープで待機し、ボタン押下やBLEアドバタイズ検知でウェイクアップする設計が取られる。年1回の電池交換を目標とする製品が多い。

LPWAセンサーネットワーク

LoRaWANSigfoxなどのLPWA通信を使ったセンサーは、1時間に1回程度のデータ送信しか行わないため、残り時間はすべてディープスリープで待機する。単三電池2本で5〜10年の動作寿命が要求される。

ウェアラブルデバイス

心拍センサー、歩数計などのウェアラブルは、連続センシングが不要なときにディープスリープを挟む設計を取る。加速度センサーに付属する動き検知回路(WakeOnMotion機能)を活用し、デバイスが静止しているときだけディープスリープに入ることができる。

実装・開発のポイント

1. RTCメモリの有効活用

ディープスリープをまたいで状態を保持するためにRTCメモリを使う。ただし容量は限られているため、保持するデータを最小限に絞る設計が重要である。

// 良い例: 必要最小限の状態をRTCメモリに保存
RTC_DATA_ATTR struct {
    uint32_t sequence_number;
    int16_t  last_temperature_x10;  // 0.1℃単位でint16_tに収める
    uint8_t  error_flags;
    uint8_t  reserved;
} rtc_state;

// 悪い例: 大きなバッファをRTCに置く(メモリ不足になる)
// RTC_DATA_ATTR char large_buffer[4096];  // やってはいけない

2. ペリフェラルの完全停止

ディープスリープ移行前に、外付け部品(センサー、通信モジュール、LEDなど)の電源を確実に切る必要がある。MCUのGPIOでFETをコントロールして外部電源をスイッチする方法が一般的である。

// 外部センサー電源制御(FETでスイッチング)
#define SENSOR_POWER_PIN GPIO_NUM_26

void power_down_peripherals(void) {
    // センサーへの電源供給を遮断
    gpio_set_level(SENSOR_POWER_PIN, 0);  // FET オフ
    
    // 遮断後の安定待ち
    vTaskDelay(pdMS_TO_TICKS(10));
}

void power_up_peripherals(void) {
    gpio_set_level(SENSOR_POWER_PIN, 1);  // FET オン
    // センサーの起動待ち
    vTaskDelay(pdMS_TO_TICKS(50));
}

3. ウェイクアップ後の初期化順序

ディープスリープ後は完全な再起動となるため、main() から全ての初期化が再実行される。ウェイクアップ原因を判定し、通常起動と区別して効率的に初期化する。

void app_main(void) {
    // まずウェイクアップ原因を確認
    esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
    
    if (cause == ESP_SLEEP_WAKEUP_UNDEFINED) {
        // 初回起動: フル初期化
        full_system_init();
        nvs_init();
        wifi_provision();
    } else {
        // ディープスリープからの復帰: 最小限の初期化
        minimal_peripheral_init();
        // RTCメモリから前回の状態を読み出す
        restore_state_from_rtc();
    }
    
    // 共通処理
    do_measurement_and_send();
    prepare_for_deep_sleep();
    esp_deep_sleep_start();
}

4. 消費電流の実測

設計した消費電流と実際の値が乖離していることは多い。Nordic PPK2(Power Profiler Kit 2)や Otii Arc などの専用ツールを使い、µA単位で実測することが重要である。

5. WDT(ウォッチドッグ)との兼ね合い

ウォッチドッグタイマーが有効なまま長時間のディープスリープに入ると、WDTがタイムアウトしてリセットがかかる。ディープスリープ前にWDTを停止(または無効化)するか、WDTのタイムアウト期間をスリープ期間より長く設定する必要がある。

他技術との比較

比較軸ディープスリープスリープモードシャットダウン
消費電流数µA〜数百nA数十µA〜数mA数百nA以下
RAM保持RTCメモリのみ保持保持しない
ウェイクアップ後の状態再起動相当継続実行完全な再起動
対応ウェイクアップソース限定的(RTC、GPIO)豊富電源ON のみ
実装の複雑さ高い(状態管理が必要)中程度低い
適用シナリオ数秒〜数分以上の待機数ms〜数秒の待機完全なオフ

ディープスリープはスリープモードよりもさらに低消費電力であるが、実装の複雑さが増す。低消費電力設計のシステム全体では、アクティブ時間の短縮(タスク処理の高速化)、ペリフェラル電源の積極的な遮断、消費電流の継続的な測定と最適化を組み合わせることが、バッテリー寿命最大化の鍵となる。

関連用語

参考リンク