一.低功耗模式介绍
系统提供了多个低功耗模式,可在 CPU 不需要运行时(例如等待外部事件时)节省功耗。由用户根据应用选择具体的低功耗模式,以在低功耗、短启动时间和可用唤醒源之间寻求最佳平衡。 当系统断电时,仍然可以通过电池供电保留备份域的数据。备份域中包含RTC实时时钟,4KB备份SRAM以及调压器,调压器为备份域和待机电路以外数字电路供电,输出电压约为1.2V。
器件有三个低功耗模式: - 睡眠模式( Cortex®-M7 内核停止,外设保持运行)
- 停止模式(所有时钟都停止)
- 待机模式(1.2 V 域断电)
此外,可通过下列方法之一降低运行模式的功耗: - 降低系统时钟速度
- 不使用 APBx 和 AHBx 外设时,将对应的外设时钟关闭。
睡眠模式只是内核停止,外接还能继续工作,I/O管脚状态没有改变。 停止模式是在睡眠模式的基础上把所有的时钟都停止了,振荡器也被禁止。此时所有外设已经停止工作。 待机模式基于 Cortex®-M7 深度睡眠模式,此时内核停止,外设也停止工作,1.2V域断电。除备份域和待机电路中的寄存器外,其他全部停止工作,SRAM和寄存器内容将丢失。只是备份域中RTC继续工作,备份ARAM数据不会丢失继续保存。此时三种低功耗模式中,待机模式可达到最低功耗。
进入低功耗模式
当 MCU 执行 WFI(等待中断)或 WFE(等待事件)指令,或者当 Cortex®-M7 系统控制寄存器中的 SLEEPONEXIT 位在从 ISR 恢复期间置 1 时,将进入低功耗模式。仅当没有中断和事件挂起时,才能通过 WFI 或 WFE 进入低功耗模式。
退出低功耗模式
在睡眠和停止模式下, MCU 根据进入低功耗模式的方式退出低功耗模式。 如果使用 WFI 指令或从 ISR 恢复的方式进入低功耗模式,则通过 NVIC 应答的任何外设中断均可唤醒器件 如果使用 WFE 指令进入低功耗模式,则 MCU 会在事件发生时立即退出低功耗模式 在待机模式下, MCU 退出低功耗模式的方式包括:外部复位(NRST 引脚)、 IWDG(独立看门狗) 复位、已使能WKUPx 引脚之一的上升沿或者 RTC 事件。stm32F7xx有六个WKUP 引脚(PA0/PA2/PC1/PC13/PI8/PI11)。
二.实验例程
本章程序在串口printf工程的基础上修改,复制串口printf的工程,修改文件夹名。击STM32F746I.ioc打开STM32cubeMX的工程文件重新配置。RTC选择内部唤醒开启RTC。PA0(WAKEUP管脚)配置为中断外部中断引脚,同时配置LED管脚。
配置RTC时间和日期,其他为默认配置。Wake UP唤醒设置在程序中设置,在此不作设置。
开启外部中断0号线中断。
生成报告以及代码,编译程序。在stm32f7xx_hal_pwr.h头文件中可以看到低功耗控制函数。
下载这两个应用程序文件,c文件放在工程目录下Src文件夹中,头文件放在Inc文件中,并在工程中添加刚才的应用程序文件。
打开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为调节编译语句,只有满足条件时才编译中间部分的语句。
第一个#if #endif语句的意思是如果没有宏定义相应低功耗模式的则编译中间的宏定义。 第二个#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
php代码:/**
* @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退出低功耗模式。
|