STM32CubeMX系列教程14:电源控制器(PWR)
睡眠模式( Cortex®-M7 内核停止,外设保持运行)
停止模式(所有时钟都停止)
待机模式(1.2 V 域断电)
降低系统时钟速度
不使用 APBx 和 AHBx 外设时,将对应的外设时钟关闭。
打开stm32fxx_lp_modes.c文件中,里面有五个低功耗测试程序。在stm32fxx_lp_modes.h文件中,可以看到函数声明和宏定义低功耗模式。而已通过去掉相应行的注释选择一种低功耗模式。
/* Exported constants --------------------------------------------------------*/ #if !defined (SLEEP_MODE) && !defined (STOP_MODE) && !defined (STANDBY_MODE)\ && !defined (STANDBY_RTC_MODE) && !defined (STANDBY_BKPSRAM_MODE) /* Uncomment the corresponding line to select the STM32F7xx Low Power mode */ //#define SLEEP_MODE #define STOP_MODE //#define STANDBY_MODE //#define STANDBY_RTC_MODE //#define STANDBY_BKPSRAM_MODE #endif #if !defined (SLEEP_MODE) && !defined (STOP_MODE) && !defined (STANDBY_MODE)\ && !defined (STANDBY_RTC_MODE) && !defined (STANDBY_BKPSRAM_MODE) #error "Please select first the target STM32F7xx Low Power mode to be measured (in stm32f7xx_lp_modes.h file)" #endif /* Exported macro ------------------------------------------------------------*/ /* Exported functions ------------------------------------------------------- */ void SleepMode_Measure(void); void StopMode_Measure(void); void StandbyMode_Measure(void); void StandbyRTCMode_Measure(void); void StandbyBKPSRAMMode_Measure(void);
在这里补充一下C语言的语法知识.#if ... #endif为调节编译语句,只有满足条件时才编译中间部分的语句。
在main.c文件前面添加头文件,定义用户按键标志变化和声明错误处理函数。
/* USER CODE BEGIN Includes */ #include "stm32f7xx_lp_modes.h" /* USER CODE END Includes */ /* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ __IO uint8_t UserButtonStatus = 0; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); /* USER CODE BEGIN PFP */ /* Private function prototypes -----------------------------------------------*/ void Error_Handler(void); /* USER CODE END PFP */
在main.c文件后面添加外部中断回调函数和错误处理函数。中断回调函数将按键标志位置1,错误处理函数打印错误信息,然后进行while循环。
/* USER CODE BEGIN 4 */
/**
* @brief This function is executed in case of error occurrence.
* @param None
* @retval None
*/
void Error_Handler(void)
{
printf("something wrong !!!\r\n");
while(1)
{
}
}
/**
* @brief EXTI line detection callbacks
* @param GPIO_Pin: Specifies the pins connected EXTI line
* @retval None
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
UserButtonStatus = 1;
}
/* USER CODE END 4 */
在main.c主函数中添加应用测试程序。程序中不断读取用户按键标志,同时LED1不断闪烁。但有WAKEUP按键按下时,跳出循环,然后等待按键释放,关闭LED1。最后根据stm32fxx_lp_modes.h中的宏定义,进入对应的低功耗模式测试函数。
/* USER CODE BEGIN 2 */ printf("\r\n******** STM32F7 LowPower Test *******\r\n"); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ printf("Press WAKEUP button to enter LP modes \r\n\r\n"); UserButtonStatus = 0; /* Wait until USER button is pressed to enter the Low Power mode */ while(UserButtonStatus == 0x00) { /* Toggle LED1 */ HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin); /* Inserted Delay */ HAL_Delay(200); } /* Loop while User button is maintained pressed */ while(HAL_GPIO_ReadPin(WAKEUP_GPIO_Port,WAKEUP_Pin) != RESET) { } /* Turn off LED1 */ HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_RESET); #if defined (SLEEP_MODE) /* Sleep Mode Entry - System Running at PLL (216MHz) - Flash 5 wait state - Instruction and Data caches ON - Prefetch ON - Code running from Internal FLASH - All peripherals disabled. - Wake-up using EXTI Line (USER Button) */ printf("SleepMode!\r\nPress WAKE_UP button to wake up ...\r\n"); SleepMode_Measure(); printf("\r\nSLEEP_MODE wake up,system running continue ... \r\n"); #elif defined (STOP_MODE) /* STOP Mode Entry - RTC Clocked by LSI - Regulator in LP mode - HSI, HSE OFF and LSI OFF if not used as RTC Clock source - No IWDG - FLASH in deep power down mode - Automatic Wake-up using RTC clocked by LSI (after ~20s) */ printf("StopMode!\r\nAutomatic Wake-up using RTC clocked by LSI (after ~20s) ...\r\n"); StopMode_Measure(); MX_USART1_UART_Init(); printf("\r\nStopMode wake up ,system running continue \r\n"); #elif defined (STANDBY_MODE) /* STANDBY Mode Entry - Backup SRAM and RTC OFF - IWDG and LSI OFF - Wake-up using WakeUp Pin (PI.11) */ printf("StandbyMode!\r\nPress WAKE_UP button to wake up ...\r\n"); StandbyMode_Measure(); printf("StandbyMode wake up ,this will never be running ,something wrong!! \r\n"); #elif defined (STANDBY_RTC_MODE) /* STANDBY Mode with RTC on LSI Entry - RTC Clocked by LSI - IWDG OFF and LSI OFF if not used as RTC Clock source - Backup SRAM OFF - Automatic Wake-up using RTC clocked by LSI (after ~20s) */ printf("StandbyRTCMode!\r\nPress WAKE_UP button to wake up ...\r\n"); StandbyRTCMode_Measure(); printf("StandbyMode wake up ,this will never be running ,something wrong!! \r\n"); #elif defined (STANDBY_BKPSRAM_MODE) /* STANDBY Mode Entry - Backup SRAM ON - IWDG OFF - Wake-up using WakeUp Pin (PI.11) */ printf("StandbyBKPSRAMMode!\r\nPress WAKE_UP button to wake up ...\r\n"); StandbyBKPSRAMMode_Measure(); printf("StandbyBKPSRAMMode wake up ,this will never be running ,something wrong!! \r\n"); #endif } /* USER CODE END 3 */ }
此处也用到条件编译语句。例如stm32fxx_lp_modes.h头文件中宏定义STOP_MODE。则程序编译的时候只会编译STOP_MODE选项中的语句。其他的语句不会编译进程序,不会写入stm32的flash中。可以在stm32fxx_lp_modes.h头开启不同的宏选择编译对应不同的语句。
下面我们来详细分析一下各种低功耗模式的运行流程。
1.SLEEP_MODE
/**
* @brief This function configures the system to enter Sleep mode for
* current consumption measurement purpose.
* Sleep Mode
* ==========
* - System Running at PLL (216MHz)
* - Flash 5 wait state
* - Instruction and Data caches ON
* - Prefetch ON
* - Code running from Internal FLASH
* - Wakeup using EXTI Line (USER Button)
* @param None
* @retval None
*/
void SleepMode_Measure(void)
{
/* Suspend Tick increment to prevent wakeup by Systick interrupt.
Otherwise the Systick interrupt will wake up the device within 1ms (HAL time base) */
HAL_SuspendTick();
/* Request to enter SLEEP mode */
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
/* Resume Tick interrupt if disabled prior to sleep mode entry */
HAL_ResumeTick();
}
睡眠模式Cortex®-M7 内核停止,程序以WFI指令进入睡眠模式,所以只要产生任意中断都会退出睡眠模式。所以进入睡眠模式前先调用HAL_SuspendTick()函数挂起系统滴答定时器,否则将会被系统滴答定时器(SysTick)中断在1ms内唤醒。程序运行到HAL_PWR_EnterSLEEPMode()函数时,系统进入睡眠模式,程序停止运行。当按下WAKEUP按键时,触发外部中断0,此时系统被唤醒。继续执行HAL_ResumeTick()语句回复系统滴答定时器。
2.STOP_MODE
/**
* @brief This function configures the system to enter Stop mode with RTC
* clocked by LSE or LSI for current consumption measurement purpose.
* STOP Mode with RTC clocked by LSE/LSI
* =====================================
* - RTC Clocked by LSE or LSI
* - Regulator in LP mode
* - HSI, HSE OFF and LSI OFF if not used as RTC Clock source
* - No IWDG
* - FLASH in deep power down mode
* - Automatic Wakeup using RTC clocked by LSE/LSI (~20s)
* @param None
* @retval None
*/
void StopMode_Measure(void)
{
RTCHandle.Instance = RTC;
/* Configure RTC prescaler and RTC data registers as follow:
- Hour Format = Format 24
- Asynch Prediv = Value according to source clock
- Synch Prediv = Value according to source clock
- OutPut = Output Disable
- OutPutPolarity = High Polarity
- OutPutType = Open Drain */
RTCHandle.Init.HourFormat = RTC_HOURFORMAT_24;
RTCHandle.Init.AsynchPrediv = RTC_ASYNCH_PREDIV;
RTCHandle.Init.SynchPrediv = RTC_SYNCH_PREDIV;
RTCHandle.Init.OutPut = RTC_OUTPUT_DISABLE;
RTCHandle.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
RTCHandle.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
if(HAL_RTC_Init(&RTCHandle) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
/*## Configure the Wake up timer ###########################################*/
/* RTC Wakeup Interrupt Generation:
Wakeup Time Base = (RTC_WAKEUPCLOCK_RTCCLK_DIV /(LSI))
Wakeup Time = Wakeup Time Base * WakeUpCounter
= (RTC_WAKEUPCLOCK_RTCCLK_DIV /(LSI)) * WakeUpCounter
==> WakeUpCounter = Wakeup Time / Wakeup Time Base
To configure the wake up timer to 20s the WakeUpCounter is set to 0xA017:
RTC_WAKEUPCLOCK_RTCCLK_DIV = RTCCLK_Div16 = 16
Wakeup Time Base = 16 /(~32.768KHz) = ~0,488 ms
Wakeup Time = ~20s = 0,488ms * WakeUpCounter
==> WakeUpCounter = ~20s/0,488ms = 40983 = 0xA017 */
HAL_RTCEx_SetWakeUpTimer_IT(&RTCHandle, 0xA017, RTC_WAKEUPCLOCK_RTCCLK_DIV16);
/* FLASH Deep Power Down Mode enabled */
HAL_PWREx_EnableFlashPowerDown();
/* Enter Stop Mode */
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
/* Configures system clock after wake-up from STOP: enable HSE, PLL and select
PLL as system clock source (HSE and PLL are disabled in STOP mode) */
SYSCLKConfig_STOP();
/* Disable Wake-up timer */
if(HAL_RTCEx_DeactivateWakeUpTimer(&RTCHandle) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
}
停止模式Cortex®-M7 内核停止,外设也停止工作,所有外设时钟也关闭。此处设置了RTC唤醒。RTC时钟配置为外部时钟,频率为32.768KHz。经过16分频后的时基为16 /(~32.768KHz) = ~0,488 ms。若要20s后唤醒,则唤醒计数器的值为~20s/0,488ms = 40983 = 0xA017。由于停止模式PLL、HSI、HSE RC振荡器均被禁止,所以系统被唤醒(RTC唤醒或WAKUP按键外部中断唤醒)后需要重新配置系统时钟,同时关闭WAKEUP定时器。 由于外设时钟停止,所以程序返回main()函数中也需要重新初始化串口才能打印输出信息。
#elif defined (STOP_MODE)
/* STOP Mode Entry
- RTC Clocked by LSI
- Regulator in LP mode
- HSI, HSE OFF and LSI OFF if not used as RTC Clock source
- No IWDG
- FLASH in deep power down mode
- Automatic Wake-up using RTC clocked by LSI (after ~20s)
*/
printf("StopMode!\r\nAutomatic Wake-up using RTC clocked by LSI (after ~20s) ...\r\n");
StopMode_Measure();
MX_USART1_UART_Init();
printf("\r\nStopMode wake up ,system running continue \r\n");
3.STANDBY_MODE
/**
* @brief This function configures the system to enter Standby mode for
* current consumption measurement purpose.
* STANDBY Mode
* ============
* - Backup SRAM and RTC OFF
* - IWDG and LSI OFF
* - Wakeup using WakeUp Pin (PI.11)
* @param None
* @retval None
*/
void StandbyMode_Measure(void)
{
/* Disable all used wakeup sources: Pin1(PA.0) */
HAL_PWR_DisableWakeUpPin(PWR_WAKEUP_PIN1);
/* Clear the related wakeup pin flag */
__HAL_PWR_CLEAR_WAKEUP_FLAG(PWR_WAKEUP_PIN_FLAG1);
/* Re-enable all used wakeup sources: Pin1(PA.0) */
HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);
/* Request to enter STANDBY mode */
HAL_PWR_EnterSTANDBYMode();
}
待机模式Cortex®-M7 深度睡眠模式,此时内核停止,外设也停止工作,1.2V域断电,SRAM和寄存器内容将丢失。待机模式唤醒后是重新运行程序,相当于重启,而不是在程序原来的位置继续运行。待机模式只能从WAKEUP引脚上升沿或下降沿,RTC,复位引脚,IWDG(独立看门狗) 复位唤醒。不能通过其他中断唤醒。前面睡眠模式和停止模式可以通过WAKEUP引脚的外部中断唤醒,但是待机模式不能通过外部中断唤醒。 程序中先失能WAKUP引脚,清除唤醒引脚标志,然后使能WAKEUP 1号管脚,即PA0.stm32F7xx WAKEUP引脚一共有五个,分别为PA0/PA2/PC1/PC13/PI8/PI11。 待机模式中只有备份域还在工作,可以通过RTC唤醒和通过备SRAM备份数据。具体可以参考程序中STANDBY_RTC_MODE和STANDBY_BKPSRAM_MODE。这里不在详细讲解。
修改stm32fxx_lp_modes.h头文件中的宏定义注释选择对应低功耗模式,编译程序并下载到开发板。打开串口调试助手,设置波特率为115200。按下Open746I开发板中WAKEUP按键进入低功耗模式,再次按下按键或者等待20s退出低功耗模式。