你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】stm32L低功耗程序框架

[复制链接]
STMCU小助手 发布时间:2021-11-18 22:00
MCU:stm32L031K6T6

芯片的主要的低功耗特性
Features
• Ultra-low-power platform
– 1.65 V to 3.6 V power supply
– -40 to 125 °C temperature range
– 0.23 µA Standby mode (2 wakeup pins)
– 0.35 µA Stop mode (16 wakeup lines)
– 0.6 µA Stop mode + RTC + 8 KB RAM retention
– Down to 76 µA/MHz in Run mode
– 5 µs wakeup time (from Flash memory)
– 41 µA 12-bit ADC conversion at 10 ksps
• Core: Arm® 32-bit Cortex®-M0+
– From 32 kHz up to 32 MHz max.
– 0.95 DMIPS/MHz

功耗当然越低越好咯,但是低功耗是要付出代价的,看下各种功耗下的时钟、RAM、IO、寄存器等的运行情况,如下:

20181208130406359.png

2018120813061059.png

20181208130715752.png



我们选用的当然是最最低功耗的standby模式了:

standby模式BKP备份寄存器能够使用
standby模式LSI和LSE两个晶振源可以使用
standby模式可以用RTC或Wakeup PIN能够唤醒
注意 standby模式下RAM里面的数据是不保存的
主程序框架
  1. ...
  2. int main(void){
  3.         HAL_Init();
  4.         
  5.         SystemClock_Config();
  6.         
  7.         MX_GPIO_Init();
  8.         MX_DMA_Init();
  9.         MX_ADC_Init();
  10.         MX_IWDG_Init();
  11.         MX_SPI1_Init();
  12.         MX_TIM2_Init();
  13.         ...
  14.         
  15.         SystemPower_Config();        //PWR配置
  16.         
  17.         BSP_Init();        //板级支持包外设初始化
  18.         
  19.         BAK = get_bak_param();        //恢复备份的数据
  20.         
  21.          while(1){
  22.                 ...        
  23.                 //主程序体
  24.                
  25.         }
  26. }
复制代码

重要函数实现
1. PWR配置
  1. void SystemPower_Config(void){
  2.         __HAL_RCC_PWR_CLK_ENABLE();

  3.         HAL_PWREx_EnableUltraLowPower();

  4.         HAL_PWREx_EnableFastWakeUp();
  5. }
复制代码

2. 进入standby模式
1.先备份数据
set_bak_param(BAK);
2.进入standby模式
pwr_standby();

  1. void pwr_standby(void){
  2.         if(__HAL_PWR_GET_FLAG(PWR_FLAG_SB) != RESET){
  3.                 __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);
  4.         }
  5.         
  6.         __HAL_RCC_PWR_CLK_ENABLE();               
  7.         
  8.         //stm32L031K6 的PA0和PA2可以作为唤醒引脚
  9.         HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);
  10.         HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN3);
  11.         
  12.         /* Clear all related wakeup flags*/
  13.         __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);

  14.         HAL_PWR_EnterSTANDBYMode();
  15. }
复制代码

3. 唤醒
唤醒没什么好说的,standby模式下唤醒,程序跟上电复位没什么区别,RAM里面数据都没了,但是BKP中的数据仍然存在;
这里暂时就把唤醒当做是重新上电吧,后面说到BKP的时候再区别处理;

4. 数据备份和恢复
• Memories
– Up to 32-Kbyte Flash with ECC
– 8-Kbyte RAM
– 1-Kbyte of data EEPROM with ECC
– 20-byte backup register
– Sector protection against R/W operation
如果需要备份的数据比较少,不超过20byte,那么可以使用backup寄存器备份数据;如果大于20byte但是不超过1Kbytes可以用MCU内部的EEPROM备份数据;超过1Kbytes可以选用别的功耗模式,或者可以选用外部flash或EEPROM等介质存储数据咯

  1. //**设计结构体用来存储备份的数据**
  2. typedef struct bak_t{
  3.         uint32_t        RTC_STA;
  4.         ...        //根据自己的需要设计结构体吧
  5. }BAKTypeDef;
复制代码
4.1 用BKP备份和恢复数据
  1. typedef struct bkp_t{
  2.         uint32_t        DR0;        
  3.         uint32_t        DR1;
  4.         uint32_t        DR2;
  5.         uint32_t        DR3;
  6.         uint32_t        RTC_STA;        //rtc init sta
  7. }BKPTypeDef;

  8. void bkp_init(void){
  9.         hrtc.Instance = RTC;
  10.         BKPTypeDef bkp;
  11.         if(0xaa55aa55 != get_bkp().RTC_STA){        //判断初始化RTC
  12.                 printf("rtc init\r\n");
  13.                 HAL_RTC_Init(&hrtc);
  14.                 bkp.DR0= bkp.DR1= bkp.DR2= bkp.DR3 = 0;
  15.                 bkp.RTC_STA = 0xaa55aa55;
  16.                 set_bkp(&bkp);
  17.         }
  18. }

  19. BKPTypeDef get_bkp(void){
  20.         BKPTypeDef bkp;
  21.         bkp.DR0= HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR0);
  22.         bkp.DR1= HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1);
  23.         bkp.DR2= HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR2);
  24.         bkp.DR3 = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR3);
  25.         bkp.RTC_STA = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR4);
  26.         return bkp;
  27. }

  28. void set_bkp(BKPTypeDef *bkp){
  29.         HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR0, bkp->DR0);
  30.         HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, bkp->DR1);
  31.         HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR2, bkp->DR2);
  32.         HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR3, bkp->DR3);
  33.         HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR4, bkp->RTC_STA);
  34. }
复制代码

4.2 用EEPROM备份和恢复数据
  1. bool DATAEEPROM_write(uint16_t addr_offset, uint8_t *pData, uint16_t Size){
  2.         if(HAL_ERROR == HAL_FLASHEx_DATAEEPROM_Unlock()){
  3.                 printf("Flash EEPROM Unlock failed!!!\n");
  4.                 return false;
  5.         }
  6.         if(DATA_EEPROM_BASE+addr_offset > DATA_EEPROM_END){
  7.                 printf("Flash EEPROM Address Error!!!\n");
  8.                 return false;
  9.         }
  10.         
  11. //        HAL_FLASHEx_DATAEEPROM_Erase(DATA_EEPROM_BASE);
  12.         for(uint16_t i=0;i<Size;i++){
  13.                 HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_BYTE, DATA_EEPROM_BASE+addr_offset+32*i, pData<i>);
  14.       </i>  }

  15.         if(HAL_ERROR == HAL_FLASHEx_DATAEEPROM_Lock()){
  16.                 printf("Flash EEPROM Lock Failed!!!\n");
  17.                 return false;
  18.         }
  19.         
  20.         return true;
  21. }

  22. bool DATAEEPROM_read(uint16_t addr_offset, uint8_t *pData, uint16_t Size){
  23.         if(Size > DATAEEPROM_MAX_SIZE){
  24.                 printf("Size is too long!\r\n");
  25.                 return false;
  26.         }
  27.         if(DATA_EEPROM_BASE+addr_offset > DATA_EEPROM_END){
  28.                 printf("Flash EEPROM Address Error!!!\n");
  29.                 return false;
  30.         }
  31.         
  32.         uint8_t tmp[DATAEEPROM_MAX_SIZE] = {0};
  33.         
  34.         for(uint16_t i=0;i<Size;i++){
  35.                 tmp = *(uint32_t*)(DATA_EEPROM_BASE+addr_offset+32*i);
  36.         }
  37. #if 0        
  38.         for(uint16_t i=0;i<Size;i++){
  39.                 printf("tmp[%d]:%x\r\n",i,tmp);
  40.         }
  41. #endif        
  42.         memcpy(pData, tmp, Size);
  43.         
  44.         return true;
  45. }
复制代码

5. 区别处理
如果上电复位的时候你要让屏幕显示A画面,而唤醒之后你要让屏幕显示B画面,那该怎么区分MCU是上电复位还是wakeup的呢?
我们有一个重要的寄存器呀backup register
如果是上电复位那backup register里面的数据全部都是乱数据;
如果是wakeup那读取进入standby模式之前备份的特定的数据,如果数据对上了就是wakeup,如果没有对上,那就是上电复位了;上面的程序中我们用BKP.RTC_STA==0xaa55aa55 来判断是那种模式启动的MCU;

  1. if(0xaa55aa55 == BKP.RTC_STA){
  2.         ...
  3.         //显示B画面
  4. }else{
  5.         ...
  6.         //显示A画面
  7. }
复制代码

总结
可以选用多种低功耗模式,sleep模式、stop模式、standby模式,其中standby模式功耗最低。
选用standby模式,进入低功耗之后RAM中没有数据了,且只能用特定的且已经配置了的PIN脚来唤醒MCU;
standby模式的程序框架为:

XAJH}9J[55VNOK[(ITBB]YP.png

收藏 评论0 发布时间:2021-11-18 22:00

举报

0个回答

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版