STM32 低功耗设计

STM32L431 低功耗设计 笔记


STM32L4七大工作模式

参照《STM32L4A6xG Datasheet》描述了7种工作模式

睡眠模式 Sleep mode

  • 在睡眠模式下,仅CPU核在睡觉,因此程序处于睡觉前状态暂停。程序的运行态主要由CPU核寄存器、RAM内的数据相关。所谓CPU睡眠指CPU不会再进行取指、译码、执行的动作,CPU睡眠后相关寄存器保持不变,RAM内数据保持不变。
  • 当发生唤醒事件时,所有外设都可以继续运行,并且可以唤醒CPU。程序从执行对应的中断/事件处理代码,然后从睡眠前的状态继续执行。

低功耗运行/睡眠模式
低功耗运行模式Low-power run (LPRun): 这个模式下,CPU可以运行程序,但是跑的较慢。

  • 该模式可通过低功耗稳压器Low-Power Regulator为内核逻辑电路提供的电压工作来实现,显然降低工作电压可显著降低功耗。
  • 降低CPU的工作频率,CPU频率限制为2 MHz。独立时钟外设可以由HSI16提供时钟。
    低功耗睡眠模式Low-power sleep (LPSleep):仅低功耗运行模式可进入该模式。仅CPU时钟停止,当被唤醒时,系统将恢复为低功耗运行模式LPRun。

停止模式 STOP
提供三种停止模式:停止0,停止1和停止2模式

  • 停止模式可实现最低功耗,同时保留SRAM和寄存器的内容。由供电的所有时钟都停止运行,PLL,MSI RC,HSI16
  • RC和HSE晶体振荡器被禁用,但LSE或LSI时钟处于运行状态。
  • RTC可以保持运行状态(是通过软件配置可实现带RTC的停止模式,以及不带RTC的停止模式)。
  • 另外某些具有唤醒功能的外设可以在停止模式下启用HSI16 RC振荡器,以检测其唤醒事件。

差异点:

  • 三种模式的内部供电电源不一样,Stop0由MR(Main Regulator)提供,而Stop1/Stop2则由LPR(Low PowerRegulator提供)。
  • 唤醒源Stop2支持的唤醒源相比Stop0/Stop1少一些
  • 所需功耗则是Stop0>Stop1>Stop2,Stop0由MR供电,所以三种模式里功耗相对略大一些。
  • 唤醒时间则是Stop0<Stop1<Stop2。

相同点

  • CPU、FLASH都处于停止运行状态,而SRAM仍然处于运行,这意味着内存里的内容会保持住。LSE(Low Speed External)/LSI(Low Speed Internal)时钟运行为唤醒源提供运行时钟。

待机/关机模式
区别基本就是 唤醒源不一样,具体看下面图。

待机模式Standby mode:

  • 待机模式用于通过BOR实现低功耗。内部稳压器已关闭,因此由供电的所有电路都被关闭, PLL,MSI RC,HSI16 RC和HSE晶体振荡器等时钟电路也处于关闭状态。
  • RTC可以设置为运行状态(因此与Stop模式类似,可通过软件配置实现带RTC的待机模式,不带RTC的待机模式)。

关机模式 Shutdown mode:

  • 关机模式可实现最低功耗。内部稳压器已关闭,因此电源已关闭。PLL,HSI16,MSI,LSI和HSE振荡器也被关闭。
  • 进入待机模式后,除了备份域和待机电路中的寄存器外,SRAM1和寄存器内容都会丢失。但SRAM2可配置为数据保持状态。
  • RTC可以保持活动状态(同样可以通过软件配置成带RTC的关机模式,不带RTC的关机模式)。BOR在关机模式下不可用。在此模式下无法监视电源电压,因此不支持切换到备份域。除了备份域中的寄存器外,SRAM1,SRAM2和寄存器内容都会丢失。
  • 当发生外部复位也即NRST引脚检测到复位事件,WKUP引脚事件(可配置成上升或下降沿触发模式)或RTC事件(警报,定期唤醒,时间戳,篡改)时,设备退出关机模式。唤醒后的系统时钟为MSI,频率为4MHz。
  • 当发生外部复位(NRST引脚)、IWDG复位、WKUP唤醒引脚事件(上升沿/下降沿)或RTC事件(警报,定期唤醒,时间戳,篡改)或检测到故障时,设备退出待机模式。唤醒后的系统时钟由MSI提供,最高可为8 MHz。

STM32L4模式概述

在这里插入图片描述

设计思路

  1. 关闭所有开启的外设使能
  2. 把引脚设置成模拟输入或者浮空输入
  3. 关闭外设时钟
  4. 失能PVD、PVM以及VREFBUF。 L4参考手册P149
  5. 关闭或者挂起SysTick定时器。 L4参考手册P150
  6. 所有中悬挂断标志都要清除,挂起或者关闭SysTick定时器就不会产生中断标志。
  7. 当退出低功耗时,要重设时钟,可以通过STOPWUCK 来设置,就不用再次设置系统时钟了,使用外设要重新初始化,RTC和看门狗就不用了。

完成上面流程之后发现功耗还是很高总结一下耗电的来源
功耗主要来自这几个地方:

  1. HSE / LSE 的外部晶振功耗肯定比相对应的HSI / MSI / LSI要高
  2. 尽量关闭PLL,这个东西消耗电流达到了200uA
  3. 运行主频是很耗电的,够用就好,尽量使用HSE 4M的方式,实际中我使用8M进行分频的
  4. HCLK也很耗电,对其分频可以节省电能
  5. 电压也与功耗 有关,虽然关系不大,也是可见的关系,3.3V比1.8V的电压,功耗还是大了很多
  6. 外部功耗大硬件电路可以设计MOS管进行开关控制,用到时打开,休眠考虑关闭
  7. 启动方式可能会影响功耗?目前时从Flash中启动,从SRAM启动应该功耗会低一点。目前没做测试,有待更新

手册中查到的运行功耗:
运行模式下的电流消耗取决于几个参数。

  • 执行的二进制代码(程序本身+编译器影响)
  • 程序在内存中的位置
  • 设备软件配置
  • I/O引脚负载和开关率
  • 溫度
  • 从闪存或SRAM执行
  • 当从Flash中执行时:ART加速器配置(Cache,预取)。
  • 从SRAM执行时:SRAM1或SRAM2。

进入低功耗钱关闭不用的串口或者IIC或者SPI等通信设备。 如UART

HAL_UART_MspDeInit(&huart1);//该函数会关闭中断,清空内部寄存器,并且设置引脚为GPIO模式。所以可以达到降低功耗的目的。

在唤醒之后应该开启串口中断

HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
HAL_NVIC_SetPriority(USART2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART2_IRQn);
HAL_NVIC_SetPriority(USART3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART3_IRQn);

低功耗模式

1.睡眠模式
在睡眠模式中,仅关闭了内核时钟,内核停止运行,但其片上外设,CM3 核心的外设全都还照常运行。有两种方式进入睡眠模式,它的进入方式决定了从睡眠唤醒的方式,分别是 WFI(wait for interrupt)WFE(wait for event),即由等待“中断”唤醒和由“事件”唤醒。

  • 立即睡眠: 在执行 WFI WFE 指令时立即进入睡眠模式。
  • 退出时睡眠: 在退出优先级最低的中断服务程序后才进入睡眠模式。
  • 进入方式: 内核寄存器的 SLEEPDEEP=0 ,然后调用 WFI
    WFE 指令即可进入睡眠模式;SLEEPONEXIT=1 时,进入“退出时睡眠”模式。
  • 唤醒方式: 如果是使用 WFI 指令睡眠的,则可使用任意中断唤醒;如果是使用 WFE 指令睡眠的,则由事件唤醒。
  • 睡眠时: 关闭内核时钟,内核停止,而外设正常运行,在软件上表现为不再执行新的代码。这个状态会保留睡眠前的内核寄存器、内存的数据。
  • 唤醒延迟: 无延迟。
  • 唤醒后: 若由中断唤醒,先进入中断,退出中断服务程序后,接着执行 WFI 指令后的程序;若由事件唤醒,直接接着执行 WFE 后的程序。

2.停止模式
在停止模式中,进一步关闭了其它所有的时钟,于是所有的外设都停止了工作,但由于其 1.8V 区域的部分电源没有关闭,还保留了内核的寄存器、内存的信息,所以从停止模式唤醒,并重新开启时钟后,还可以从上次停止处继续执行代码。停止模式可以由任意一个外部中断(EXTI)唤醒,在停止模式中可以选择电压调节器为开模式或低功耗模式。

  • 调压器低功耗模式: 在停止模式下调压器可工作在正常模式或低功耗模式,可进一步降低功耗。

  • 进入方式: 内核寄存器的 SLEEPDEEP=1 ,PWR_CR 寄存器中的 PDDS=0 ,然后调用 WFIWFE
    指令即可进入停止模式;PWR_CR 寄存器的 LPDS=0 时,调压器工作在正常模式, LPDS=1 时工作在低功耗模式。

  • 唤醒方式: 如果是使用 WFI 指令睡眠的,可使用任意 EXTI 线的中断唤醒;如果是使用 WFE 指令睡眠的,可使用任意配置为事件模式的
    EXTI 线事件唤醒。

  • 停止时: 内核停止,片上外设也停止。这个状态会保留停止前的内核寄存器、内存的数据。

  • 唤醒延迟: 基础延迟为 HSI 振荡器的启动时间,若调压器工作在低功耗模式,还需要加上调压器从低功耗切换至正常模式下的时间。

  • 唤醒后: 若由中断唤醒,先进入中断,退出中断服务程序后,接着执行 WFI 指令后的程序;若由事件唤醒,直接接着执行 WFE 后的程序。唤醒后,STM32 会使用 HSI 作为系统时钟。

3.待机模式
待机模式,它除了关闭所有的时钟,还把 1.8V 区域的电源也完全关闭了,也就是说,从待机模式唤醒后,由于没有之前代码的运行记录,只能对芯片复位,重新检测 boot 条件,从头开始执行程序。它有四种唤醒方式,分别是 WKUP(PA0)引脚的上升沿,RTC 闹钟事件,NRST 引脚的复位和 IWDG(独立看门狗)复位。

  • 进入方式: 内核寄存器的 SLEEPDEEP=1 ,PWR_CR 寄存器中的 PDDS=1 ,PWR_CR 寄存器中的唤醒状态位 WUF=0 ,然后调用 WFI WFE 指令即可进入待机模式。
  • 唤醒方式: 通过 WKUP 引脚的上升沿,RTC 闹钟、唤醒、入侵、时间戳事件或 NRST 引脚外部复位及 IWDG 复位唤醒。
  • 待机时: 内核停止,片上外设也停止;内核寄存器、内存的数据会丢失;除复位引脚、RTC_AF1 引脚及 WKUP 引脚,其它 I/O 口均工作在高阻态。
  • 唤醒延迟: 芯片复位的时间。
  • 唤醒后: 相当于芯片复位,在程序表现为从头开始执行代码。

WFI与WFE命令

我们了解到进入各种低功耗模式时都需要调用 WFI 或 WFE 命令,它们实质上都是内核指令,在库文件 core_cm3.h 中把这些指令封装成了函数。

/** brief 等待中断
  等待中断 是一个暂停执行指令
  暂停至任意中断产生后被唤醒
*/
#define __WFI        __wfi 

/** brief 等待事件
  等待事件 是一个暂停执行指令
  暂停至任意事件产生后被唤醒
*/
#define __WFE        __wfe

对于这两个指令,我们应用时一般只需要知道,调用它们都能进入低功耗模式,需要使用函数的格式“__WFI();”和“__WFE();”来调用(因为__wfi 及__wfe 是编译器内置的函数,函数内部调用了相应的汇编指令)。
其中 WFI 指令决定了它需要用中断唤醒,而 WFE 则决定了它可用事件来唤醒。

转载 Leung_ManWah 大佬文章 原文链接

代码实现

实验中仅使用串口1,通过串口发送字符5,启动STOP2模式,通过PC9引脚唤醒 ,系统时钟2M来达到最低功耗

STM32CubeMX设置

串口1设置

中断设置 高电平唤醒

编写进入低功耗前代码


			printf("\r\n=== Power Stop ===\r\n");
			
			HAL_DBGMCU_DisableDBGStopMode();
			HAL_DBGMCU_DisableDBGSleepMode();
			HAL_DBGMCU_DisableDBGStandbyMode();//关闭调试接口
			/* 关闭串口1时钟 */
			HAL_UART_DeInit(&huart1); 
			__HAL_RCC_USART1_CLK_DISABLE();
			/* 设置所有引脚为模拟输入 */
			GPIO_InitTypeDef GPIO_InitStruct;
			GPIO_InitStruct.Pin = GPIO_PIN_All;
			GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
			GPIO_InitStruct.Pull = GPIO_NOPULL;
			GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
			HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);
			HAL_GPIO_Init(GPIOB,&GPIO_InitStruct);
			HAL_GPIO_Init(GPIOC,&GPIO_InitStruct);
			/* 关闭所有GPIO时钟 */
			__HAL_RCC_GPIOA_CLK_DISABLE();
			__HAL_RCC_GPIOB_CLK_DISABLE();
			__HAL_RCC_GPIOC_CLK_DISABLE();//
			/*打开中断引脚时钟*/
			/* GPIO Ports Clock Enable */
			__HAL_RCC_GPIOC_CLK_ENABLE();
			/*Configure GPIO pin : PtPin */
			GPIO_InitStruct.Pin = PWR_EN_Pin;
			GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
			GPIO_InitStruct.Pull = GPIO_PULLDOWN;
			HAL_GPIO_Init(PWR_EN_GPIO_Port, &GPIO_InitStruct);
			/* EXTI interrupt init*/
			HAL_NVIC_SetPriority(EXTI9_5_IRQn, 6, 0);
			HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
			
			HAL_PWR_DisablePVD();//禁用电源电压检测器(PVD)
			HAL_SYSCFG_DisableVREFBUF();//禁用内部电压基准缓冲器(VREFBUF)
			HAL_SYSCFG_DisableIOAnalogSwitchBooster();//禁用I/O模拟量开关电压升压器。
			__HAL_PWR_PVM3_EXTI_DISABLE_RISING_FALLING_EDGE();//禁用PVM3中断
			__HAL_PWR_PVM4_EXTI_DISABLE_RISING_FALLING_EDGE();//禁用PVM4中断
			
			// 唤醒后选择哪个启动时钟源
			__HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_MSI);
			// 降低核心工作电压,需要根据实际工作频率设置,建议在Cubemx内的RCC项目中配置
			__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);		
			HAL_SuspendTick(); // 暂停滴答时钟,防止通过滴答时钟中断唤醒
			__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);  // 清除唤醒标记			
			__HAL_RCC_PWR_CLK_ENABLE();	//运行电源管理时钟  
//			HAL_DBGMCU_EnableDBGStopMode();			//stop模式下进行调试
//			HAL_PWR_EnableBkUpAccess();
			HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);    	//进入stop 2 mode

编写退出低功耗程序

			
			SystemClock_Config(); // 刚从STOP模式唤醒时钟默认使用内部高速8M时钟,所以需要重新配置时钟
			HAL_ResumeTick(); // 被唤醒后,恢复滴答时钟		
			MX_GPIO_Init(); 
			MX_USART1_UART_Init();
			HAL_UART_Receive_IT(&huart1, &usart1_buf.aRxBuff, 1);
		
			// 获取重新配置后的时钟状态
			SYSCLK_Frequency = HAL_RCC_GetSysClockFreq();
			HCLK_Frequency = HAL_RCC_GetHCLKFreq();
			PCLK1_Frequency = HAL_RCC_GetPCLK1Freq();
			PCLK2_Frequency = HAL_RCC_GetPCLK2Freq();
			SYSCLK_Source = __HAL_RCC_GET_SYSCLK_SOURCE();
			HAL_Delay(200);					
			printf("\r\n 重新配置后的时钟状态:\r\n");
			printf(" SYSCLK 频率:%d,\r\n HCLK 频率:%d,\r\n PCLK1 频率:%d,\r\n PCLK2 频率:%d,\r\n 时钟源:%d (0 表示 HSI,8 表示 PLLCLK)\n",SYSCLK_Frequency,HCLK_Frequency,PCLK1_Frequency,PCLK2_Frequency,SYSCLK_Source);
			HAL_Delay(200);		

下载程序 观察表电流1.01mA,串口发送‘5’成功进入低功耗,电流2.3uA左右,按下唤醒按键程序成功被唤醒。
下载程序之后
判断是否进入低功耗看是否程序停了下来。
判断是否达到低功耗的标准测功耗是否符合该模式下的功耗。
并不是进入了低功耗就代表达到了低功耗的标准。
如果做不到,请考虑是否将全部IO配置为模拟输入模式

调试问题

问题原因:低功耗模式进去有很快退出

查各种中断、事件看看有没有唤醒。

发现经常被唤醒的是系统滴答

void               HAL_SuspendTick(void);
void               HAL_ResumeTick(void);

调试模式时独立看门狗问题

/**
  * @brief  IWDG Peripherals Debug mode
  */
#if defined (DBGMCU_APB1_FZ_DBG_IWDG_STOP)
#define __HAL_DBGMCU_FREEZE_IWDG()            SET_BIT(DBGMCU->APB1FZ, DBGMCU_APB1_FZ_DBG_IWDG_STOP)
#define __HAL_DBGMCU_UNFREEZE_IWDG()          CLEAR_BIT(DBGMCU->APB1FZ, DBGMCU_APB1_FZ_DBG_IWDG_STOP)
#endif

__HAL_DBGMCU_FREEZE_IWDG() 冻结看门狗,此时在调试模式下看门狗就不会复位
__HAL_DBGMCU_UNFREEZE_IWDG()恢复看门狗


STOP模式可调试模式

/* DBGMCU Peripheral Control functions  *****************************************/
void              HAL_DBGMCU_EnableDBGSleepMode(void);
void              HAL_DBGMCU_DisableDBGSleepMode(void);
void              HAL_DBGMCU_EnableDBGStopMode(void);
void              HAL_DBGMCU_DisableDBGStopMode(void);
void              HAL_DBGMCU_EnableDBGStandbyMode(void);
void              HAL_DBGMCU_DisableDBGStandbyMode(void);

如 HAL_DBGMCU_EnableDBGStopMode,就可以在stop模式下进行调试。
HAL_DBGMCU_EnableDBGSleepMode 在Sleep模式下进行调试
HAL_DBGMCU_EnableDBGStandbyMode 在待机模式下进行调试


参考文献

  • 10
    点赞
  • 64
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值