概要
スリープモード(Sleep Mode)は、マイクロコントローラ(MCU)やプロセッサが通常動作を一時停止し、消費電力を大幅に削減するための動作状態である。CPUコアのクロックを停止したり、一部の周辺機器(ペリフェラル)への電源供給を遮断したりすることで、アクティブ時と比較して数桁単位で消費電流を低減できる。
組み込みシステム、特に電池駆動のIoTデバイスやウェアラブル機器において、スリープモードの活用は製品の電池寿命を決定的に左右する重要な設計要素である。スリープモードには深さ(スリープの度合い)によって複数の段階があり、より深いスリープ状態ほど消費電力は小さくなるが、復帰(ウェイクアップ)に要する時間は長くなる傾向がある。
一般的なスリープモードの分類としては、以下のようなものがある。
| モード名 | CPU | ペリフェラル | RAM保持 | 消費電流目安 | 復帰時間 |
|---|---|---|---|---|---|
| アイドル(Idle/Sleep) | 停止 | 動作中 | 保持 | 数mA〜数十µA | µs〜ms |
| スリープ(Light Sleep) | 停止 | 一部停止 | 保持 | 数十µA〜数µA | ms〜数ms |
| ディープスリープ(Deep Sleep) | 停止 | ほぼ停止 | 保持しない場合あり | 数µA〜数百nA | ms〜数十ms |
| シャットダウン | 停止 | 全停止 | 保持しない | 数百nA以下 | 数十ms〜 |
歴史・背景
スリープモードの概念は、コンピュータ省電力化の歴史とともに発展してきた。1990年代にACPI(Advanced Configuration and Power Interface)がPC向けに策定され、S0(動作)からS5(シャットダウン)に至る電源状態の標準化が進んだ。組み込みシステムの世界では、バッテリー駆動のポータブル機器が普及した1980〜1990年代から、各マイコンメーカーが独自のスリープモードを実装してきた。
2000年代以降、IoTの台頭とともにコネクテッドデバイスの爆発的な普及が進み、単三電池1本で数年間動作するセンサーノードのニーズが高まった。これに対応するため、各MCUベンダーはスリープ中の消費電流をnA(ナノアンペア)オーダーまで削減する技術を競い合って開発した。Nordic Semiconductor、Silicon Labs、STMicroelectronicsなどが超低消費電力MCUの分野でしのぎを削っている。
エネルギー効率に関する国際的な規制(EU ErP指令、米国Energy Starなど)も、製品のスタンバイ消費電力削減を義務付けており、スリープモードの重要性はさらに増している。
技術仕様
ARM Cortex-M系のスリープモード
ARM Cortex-Mプロセッサは、省電力のための命令として WFI(Wait For Interrupt)と WFE(Wait For Event)を提供している。
// ARM Cortex-M: WFI命令によるスリープ移行
static inline void __WFI(void) {
__asm volatile ("wfi");
}
// スリープモード移行の典型的なコード例(CMSIS使用)
void enter_sleep_mode(void) {
// SCB->SCR: SLEEPDEEP ビットを0にするとノーマルスリープ
SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
// 割り込みを有効化してからWFIで待機
__enable_irq();
__WFI();
// 割り込み発生後ここから再開
}
SLEEPDEEP ビットを1に設定すると、ディープスリープモードへの移行が有効になる。
STM32のスリープモード構成
STM32マイコンでは、HALライブラリを使って以下のようにスリープを制御できる。
#include "stm32f4xx_hal.h"
// スリープモード(CPUクロック停止、ペリフェラルは動作)
void enter_sleep(void) {
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
}
// ストップモード(ほぼすべてのクロック停止)
void enter_stop(void) {
// RTC割り込みをウェイクアップソースに設定
HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 0x1FFF, RTC_WAKEUPCLOCK_RTCCLK_DIV16);
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
// ウェイクアップ後のシステムクロック再設定
SystemClock_Config();
}
// スタンバイモード(RAMの内容は失われる)
void enter_standby(void) {
HAL_PWR_EnterSTANDBYMode();
}
ESP32のスリープモード
ESP32は豊富なスリープオプションを持つ。
#include "esp_sleep.h"
#include "driver/rtc_io.h"
void configure_sleep(void) {
// タイマーウェイクアップ: 10秒後に起動
esp_sleep_enable_timer_wakeup(10 * 1000000ULL); // µs単位
// GPIOウェイクアップの設定(Light Sleepのみ)
gpio_wakeup_enable(GPIO_NUM_4, GPIO_INTR_LOW_LEVEL);
esp_sleep_enable_gpio_wakeup();
// ライトスリープ(RAMの内容保持)
esp_light_sleep_start();
// ディープスリープ(RTCメモリのみ保持)
// esp_deep_sleep_start();
}
// ウェイクアップ原因の確認
void check_wakeup_reason(void) {
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
switch (cause) {
case ESP_SLEEP_WAKEUP_TIMER:
printf("タイマーによるウェイクアップ\n");
break;
case ESP_SLEEP_WAKEUP_GPIO:
printf("GPIOによるウェイクアップ\n");
break;
default:
printf("通常起動\n");
break;
}
}
動作原理
スリープモードの動作原理は、クロックゲーティング(Clock Gating)と電源ゲーティング(Power Gating)の組み合わせによる。
クロックゲーティングは、特定の回路ブロックへのクロック信号供給を停止する技術である。CMOSロジックでは、クロックが変化するときにのみ電力を消費する動的消費電力が支配的なため、クロックを停止すると消費電力は大幅に低下する。ただし、電源は供給されたままなので、静的消費電流(リーク電流)は残る。
電源ゲーティングは、回路ブロックへの電源供給そのものを遮断する。これによりリーク電流もほぼゼロになるが、RAMやレジスタの内容は失われる。ディープスリープモードではこの手法が使われ、RTCドメイン(Real-Time Clock)などの最小限の回路だけが通電状態を維持する。
ウェイクアップソース
スリープから復帰するためのトリガー(ウェイクアップソース)には以下がある。
| ウェイクアップソース | 概要 | 適用スリープレベル |
|---|---|---|
| 外部割り込み(GPIO) | ボタン押下、センサー信号など | 全レベル |
| RTCタイマー | 一定時間後に自動ウェイクアップ | 全レベル |
| UARTデータ受信 | 通信データ受信で起動 | ライトスリープ |
| I2C/SPIアクティビティ | 通信バスのアクティビティ | ライトスリープ |
| タッチセンサー | 静電容量変化の検出 | 一部MCU対応 |
| 内部ウォッチドッグ | タイムアウトによる強制復帰 | 全レベル |
用途・ユースケース
IoTセンサーノード
温度・湿度・CO2などを計測するIoTセンサーは、1分に1回だけ計測・送信し、残りの時間はディープスリープで待機するという設計が一般的である。例えば、アクティブ時の消費電流が10mAで、計測・送信に1秒かかるとする。ディープスリープ中の消費電流が5µAとすると、1分周期での平均消費電流は以下のように計算できる。
平均電流 = (10mA × 1秒 + 0.005mA × 59秒) / 60秒
= (10 + 0.295) / 60 mA
≈ 0.172 mA
単三電池2本(約3000mAh)の場合、連続動作(10mA)なら300時間(約12日)しか持たないが、スリープ活用なら3000 / 0.172 ≈ 17,400時間(約2年)の動作が期待できる。
ウェアラブルデバイス
スマートウォッチや健康モニタリングデバイスは、画面を消灯しているとき(大半の時間)はスリープモードに入り、加速度センサーによる手首の動き検知や時刻更新のタイミングだけ起動する設計が取られる。
スマートメータ
電気・ガス・水道のスマートメータは、数分〜数時間おきに検針データを無線送信する間、超低消費のスリープ状態を維持し、電池交換なしで10年以上の動作を目標とする。
産業用センサ
工場設備の振動・温度監視センサにおいても、異常検知の閾値を超えたときだけアラートを送信し、通常はスリープで待機するエッジ処理型の設計が省電力化に有効である。
実装・開発のポイント
1. ウェイクアップレイテンシの考慮
スリープが深いほど、ウェイクアップから実際に処理を開始するまでの時間(レイテンシ)が長くなる。リアルタイム応答が求められるアプリケーションでは、スリープの深さをレイテンシ要件に合わせて選択する必要がある。
2. ペリフェラルの状態管理
スリープ移行前にペリフェラル(UART、SPI、I2Cなど)を適切に停止し、ウェイクアップ後に再初期化する処理が必要である。
void pre_sleep_housekeeping(void) {
// 送信バッファのフラッシュ
HAL_UART_DeInit(&huart1);
// SPIの停止
HAL_SPI_DeInit(&hspi1);
// GPIO入力ピンのプルアップ/プルダウン設定
// (フローティング状態を避けてリーク電流を防止)
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_All;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
3. フローティングピンの処理
スリープ中にGPIOピンがフローティング(不定)状態になると、意図しない電流が流れリーク電流の原因になる。未使用ピンはアナログ入力モードに設定するか、プルアップ/プルダウン抵抗で固定する。
4. RTOSとの連携
FreeRTOSなどのRTOSを使用する場合、アイドルタスク(Idle Task)のフック関数内でスリープモードに移行する設計が標準的である。
// FreeRTOS: アイドルフックでスリープに移行
void vApplicationIdleHook(void) {
// すべてのタスクが待機中の場合にスリープ
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
}
5. デバッグ時の注意
スリープモード中はデバッガ(J-Link、ST-Linkなど)との通信が切断される場合がある。デバッグ時はスリープを無効化するマクロを設定しておくと作業しやすい。
#ifdef DEBUG
#define ENTER_SLEEP() // デバッグ時はスリープしない
#else
#define ENTER_SLEEP() HAL_PWR_EnterSTOPMode(...)
#endif
他技術との比較
| 観点 | スリープモード | ディープスリープ | シャットダウン |
|---|---|---|---|
| CPU状態 | 停止 | 停止 | 停止 |
| RAM保持 | 保持 | 一部保持(RTC RAM) | 保持しない |
| ペリフェラル | 動作可 | ほぼ停止 | 全停止 |
| 消費電流 | µA〜mA | nA〜µA | nA以下 |
| 復帰時間 | µs〜ms | ms〜数十ms | 数十ms以上 |
| 復帰後の状態 | そのまま継続 | 再初期化が必要な場合あり | 完全な再起動 |
| 適用場面 | 短時間の待機 | 長時間の待機 | 電源オフ相当 |
スリープモードとディープスリープの使い分けは、ウェイクアップの頻度と許容できる復帰レイテンシによって決まる。高頻度でウェイクアップが必要な場合はスリープモード、数秒〜数分単位の長い待機にはディープスリープが適している。
低消費電力設計全体の観点では、スリープモードはソフトウェアレベルの施策の一つであり、LDOやDC-DCコンバータの選択、消費電流の測定・最適化と組み合わせて総合的に取り組む必要がある。