1: PWRモジュール概要
### PWRの役割 PWR(Power Control)はSTM32マイクロコントローラの電源管理を担当し、可変電圧監視機能と低消費電力モードを実現します。可変電圧監視器(PVD)はVDD電源電圧を監視し、電圧がしきい値を超える/下回った際に中断を発生させ、緊急停止処理を実行します。 低消費電力モードには以下の3種類があります: - 睡眠モード(Sleep) - 停止モード(Stop) - 待機モード(Standby) これらはシステムが空閑時に消費電力を削減し、デバイスの運用時間を延長するための機能です。2: 電源構成図
VDDは電圧レギュレータを通じて1.8Vに降圧され、1.8V領域への電源供給を行います。
3: 低消費電力モードの選択
- HSL/HSE: 内部高速クロック(HSI)と外部高速クロック(HSE)
- 時鐘停止: 計算処理は一時停止しますが、レジスタ値は保持されます。
- 電源停止: 回路が完全に電源オフになり、データも失われます。
- 電圧レギュレータ: 1.8V領域への電源供給を担当し、停止させるとその領域が使用不可になります。
4: 睡眠モードの特徴
- WFI: 任意のNVIC応答割り込みで覚醒可能
- WFE: イベントまたは割り込みで覚醒可能(割り込みの優先度が高い)
- 1.8V領域のCPUクロックのみ停止
5: 停止モードの特徴
- PLL、HSI、HSEが無効化される
- SRAMとレジスタ値は保持される
- 外部割り込みでしか覚醒できない(内部割り込みは不可)
- 覚醒後はHSE再起動が必要
6: 待機モードの特徴
- 1.8V領域が電源オフになる
- SRAMとレジスタ値が消失
- WKUPピンやRTCアラームでしか覚醒できない
- LSI/LSEはRTCとIWDGの維持のために動作継続
7: レジスタ操作
電源管理レジスタの設定例を示します。
2: STM32F407の実装
STM32F407のコード構造はSTM32F103と同様の設計原則を採用しています。
3: 実装例
A: 睡眠モード(WFI)
外部割り込みで覚醒する例:
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "UART.h"
#include "delay.h"
#include "key.h"
int main(void)
{
HAL_Init();
sys_stm32_clock_init(RCC_PLL_MUL9);
delay_init(72);
Uart_Init(115200);
KEY_Init();
while(1)
{
printf("5\n");
HAL_Delay(1000);
printf("4\n");
HAL_Delay(1000);
printf("3\n");
HAL_Delay(1000);
HAL_PWR_DisableSleepOnExit();
SysTick->CTRL &= ~(SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk);
HAL_PWR_EnterSLEEPMode(0, PWR_SLEEPENTRY_WFI);
printf("2\n");
HAL_Delay(1000);
printf("1\n");
HAL_Delay(1000);
}
}
B: 内部割り込みによる覚醒
タイマ割り込みで睡眠モードを覚醒させる例:
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "UART.h"
#include "delay.h"
#include "key.h"
#include "IC_encoder.h"
int main(void)
{
HAL_Init();
sys_stm32_clock_init(RCC_PLL_MUL9);
delay_init(72);
Uart_Init(115200);
KEY_Init();
IC_encoder_Init(20000-1, 7200);
while(1)
{
printf("5\n");
HAL_Delay(1000);
printf("4\n");
HAL_Delay(1000);
printf("3\n");
HAL_Delay(1000);
HAL_PWR_DisableSleepOnExit();
SysTick->CTRL &= ~(SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk);
HAL_PWR_EnterSLEEPMode(0, PWR_SLEEPENTRY_WFI);
printf("2\n");
HAL_Delay(1000);
printf("1\n");
HAL_Delay(1000);
}
}
C: イベントによる覚醒
外部イベントで睡眠モードを覚醒させる例:
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "UART.h"
#include "delay.h"
#include "key.h"
int main(void)
{
HAL_Init();
sys_stm32_clock_init(RCC_PLL_MUL9);
delay_init(72);
Uart_Init(115200);
KEY_Init();
while(1)
{
printf("5\n");
HAL_Delay(1000);
printf("4\n");
HAL_Delay(1000);
printf("3\n");
HAL_Delay(1000);
HAL_PWR_DisableSleepOnExit();
SysTick->CTRL &= ~(SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk);
HAL_PWR_EnterSLEEPMode(0, PWR_SLEEPENTRY_WFE);
SysTick->CTRL |= (SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk);
printf("2\n");
HAL_Delay(1000);
printf("1\n");
HAL_Delay(1000);
}
}
D: 内部イベントによる覚醒
内部イベントで睡眠モードを覚醒させる例:
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "UART.h"
#include "delay.h"
#include "key.h"
#include "IC_encoder.h"
int main(void)
{
HAL_Init();
sys_stm32_clock_init(RCC_PLL_MUL9);
delay_init(72);
Uart_Init(115200);
KEY_Init();
IC_encoder_Init(20000-1, 7200);
while(1)
{
printf("5\n");
HAL_Delay(1000);
printf("4\n");
HAL_Delay(1000);
printf("3\n");
HAL_Delay(1000);
HAL_PWR_EnableSEVOnPend();
HAL_PWR_DisableSleepOnExit();
SysTick->CTRL &= ~(SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk);
HAL_PWR_EnterSLEEPMode(0, PWR_SLEEPENTRY_WFE);
SysTick->CTRL |= (SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk);
__HAL_TIM_CLEAR_FLAG(&PA0TIM2CH1Handleinit, TIM_FLAG_UPDATE);
NVIC_ClearPendingIRQ(TIM2_IRQn);
HAL_TIM_Base_Stop_IT(&PA0TIM2CH1Handleinit);
printf("2\n");
HAL_Delay(1000);
printf("1\n");
HAL_Delay(1000);
}
}
E: SLEEP-ON-EXITモード
すべての処理を割り込みで実行する例:
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "UART.h"
#include "delay.h"
#include "key.h"
#include "IC_encoder.h"
int main(void)
{
HAL_Init();
sys_stm32_clock_init(RCC_PLL_MUL9);
Uart_Init(115200);
KEY_Init();
HAL_PWR_EnableSleepOnExit();
IC_encoder_Init(20000-1, 7200);
while(1)
{
// 主ループは空にして割り込み処理に依存
}
}
F: 停止モード(WFI)
外部割り込みで覚醒する例:
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "UART.h"
#include "key.h"
int main(void)
{
HAL_Init();
sys_stm32_clock_init(RCC_PLL_MUL9);
Uart_Init(115200);
KEY_Init();
while(1)
{
printf("5\n");
HAL_Delay(1000);
printf("4\n");
HAL_Delay(1000);
printf("3\n");
HAL_Delay(1000);
SysTick->CTRL &= ~(SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk);
HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI);
printf("2\n");
HAL_Delay(1000);
printf("1\n");
HAL_Delay(1000);
}
}
G: 停止モード(WFE)
外部イベントで覚醒する例:
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "UART.h"
#include "key.h"
int main(void)
{
HAL_Init();
sys_stm32_clock_init(RCC_PLL_MUL9);
Uart_Init(115200);
KEY_Init();
while(1)
{
printf("5\n");
HAL_Delay(1000);
printf("4\n");
HAL_Delay(1000);
printf("3\n");
HAL_Delay(1000);
SysTick->CTRL &= ~(SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk);
HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFE);
SysTick->CTRL |= (SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk);
sys_stm32_clock_init(RCC_PLL_MUL9);
printf("2\n");
HAL_Delay(1000);
printf("1\n");
HAL_Delay(1000);
}
}
H: 待機モード
WKUPピンで覚醒する例:
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "UART.h"
#include "key.h"
int main(void)
{
HAL_Init();
sys_stm32_clock_init(RCC_PLL_MUL9);
Uart_Init(115200);
KEY_Init();
__HAL_RCC_PWR_CLK_ENABLE();
if(__HAL_PWR_GET_FLAG(PWR_FLAG_SB))
{
printf("待機モード中\n");
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);
}
else
{
printf("待機モード外\n");
}
while(1)
{
printf("5\n");
HAL_Delay(1000);
printf("4\n");
HAL_Delay(1000);
printf("3\n");
HAL_Delay(1000);
HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
HAL_PWR_EnterSTANDBYMode();
printf("2\n");
HAL_Delay(1000);
printf("1\n");
HAL_Delay(1000);
}
}
RTCアラームで覚醒する例については、別のセクションで詳細に説明します。