打印
[应用相关]

[stm32]stm32L低功耗程序框架

[复制链接]
1367|21
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
wakayi|  楼主 | 2019-6-13 14:20 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
原文:https://blog.csdn.net/slimmm/article/details/84892483

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


使用特权

评论回复
沙发
wakayi|  楼主 | 2019-6-13 14:20 | 只看该作者
功耗当然越低越好咯,但是低功耗是要付出代价的,看下各种功耗下的时钟、RAM、IO、寄存器等的运行情况,如下:

使用特权

评论回复
板凳
wakayi|  楼主 | 2019-6-13 14:21 | 只看该作者

使用特权

评论回复
地板
wakayi|  楼主 | 2019-6-13 14:21 | 只看该作者

使用特权

评论回复
5
wakayi|  楼主 | 2019-6-13 14:21 | 只看该作者

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

  • standby模式BKP备份寄存器能够使用
  • standby模式LSI和LSE两个晶振源可以使用
  • standby模式可以用RTC或Wakeup PIN能够唤醒
  • 注意 standby模式下RAM里面的数据是不保存的

使用特权

评论回复
6
wakayi|  楼主 | 2019-6-13 14:22 | 只看该作者
主程序框架


...
int main(void){
        HAL_Init();
       
        SystemClock_Config();
       
        MX_GPIO_Init();
        MX_DMA_Init();
        MX_ADC_Init();
        MX_IWDG_Init();
        MX_SPI1_Init();
        MX_TIM2_Init();
        ...
       
        SystemPower_Config();        //PWR配置
       
        BSP_Init();        //板级支持包外设初始化
       
        BAK = get_bak_param();        //恢复备份的数据
       
         while(1){
                ...       
                //主程序体
               
        }
}



使用特权

评论回复
7
wakayi|  楼主 | 2019-6-13 14:22 | 只看该作者
重要函数实现
1. PWR配置

void SystemPower_Config(void){      
       __HAL_RCC_PWR_CLK_ENABLE();
       HAL_PWREx_EnableUltraLowPower();
        HAL_PWREx_EnableFastWakeUp();
}


使用特权

评论回复
8
wakayi|  楼主 | 2019-6-13 14:23 | 只看该作者
2. 进入standby模式
1.先备份数据
set_bak_param(BAK);
2.进入standby模式
pwr_standby();


void pwr_standby(void){
        if(__HAL_PWR_GET_FLAG(PWR_FLAG_SB) != RESET){
                __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);
        }
       
        __HAL_RCC_PWR_CLK_ENABLE();               
       
        //stm32L031K6 的PA0和PA2可以作为唤醒引脚
        HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);
        HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN3);
       
        /* Clear all related wakeup flags*/
        __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);

        HAL_PWR_EnterSTANDBYMode();
}



使用特权

评论回复
9
wakayi|  楼主 | 2019-6-13 14:23 | 只看该作者
3. 唤醒
唤醒没什么好说的,standby模式下唤醒,程序跟上电复位没什么区别,RAM里面数据都没了,但是BKP中的数据仍然存在;
这里暂时就把唤醒当做是重新上电吧,后面说到BKP的时候再区别处理;

使用特权

评论回复
10
wakayi|  楼主 | 2019-6-13 14:24 | 只看该作者
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等介质存储数据咯



//**设计结构体用来存储备份的数据**typedef struct bak_t
{        
uint32_t        
RTC_STA;        
...        //根据自己的需要设计结构体吧
}BAKTypeDef;


使用特权

评论回复
11
wakayi|  楼主 | 2019-6-13 14:25 | 只看该作者
4.1 用BKP备份和恢复数据



typedef struct bkp_t{
        uint32_t        DR0;
       uint32_t        DR1;
       uint32_t        DR2;
        uint32_t        DR3;
       uint32_t        RTC_STA;        //rtc init sta
}BKPTypeDef;

使用特权

评论回复
12
wakayi|  楼主 | 2019-6-13 14:26 | 只看该作者
void bkp_init(void){
        hrtc.Instance = RTC;
        BKPTypeDef bkp;
        if(0xaa55aa55 != get_bkp().RTC_STA){        //判断初始化RTC
                printf("rtc init\r\n");
                HAL_RTC_Init(&hrtc);
                bkp.DR0= bkp.DR1= bkp.DR2= bkp.DR3 = 0;
                bkp.RTC_STA = 0xaa55aa55;
                set_bkp(&bkp);
        }
}


使用特权

评论回复
13
wakayi|  楼主 | 2019-6-13 14:27 | 只看该作者
BKPTypeDef get_bkp(void){
        BKPTypeDef bkp;
        bkp.DR0= HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR0);
        bkp.DR1= HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1);
        bkp.DR2= HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR2);
        bkp.DR3 = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR3);
        bkp.RTC_STA = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR4);
        return bkp;
}


使用特权

评论回复
14
wakayi|  楼主 | 2019-6-13 14:27 | 只看该作者
void set_bkp(BKPTypeDef *bkp){
        HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR0, bkp->DR0);
        HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, bkp->DR1);
        HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR2, bkp->DR2);
        HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR3, bkp->DR3);
        HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR4, bkp->RTC_STA);
}


使用特权

评论回复
15
wakayi|  楼主 | 2019-6-13 14:27 | 只看该作者
4.2 用EEPROM备份和恢复数据


bool DATAEEPROM_write(uint16_t addr_offset, uint8_t *pData, uint16_t Size){
        if(HAL_ERROR == HAL_FLASHEx_DATAEEPROM_Unlock()){
                printf("Flash EEPROM Unlock failed!!!\n");
                return false;
        }
        if(DATA_EEPROM_BASE+addr_offset > DATA_EEPROM_END){
                printf("Flash EEPROM Address Error!!!\n");
                return false;
        }

//        HAL_FLASHEx_DATAEEPROM_Erase(DATA_EEPROM_BASE);
        for(uint16_t i=0;i<Size;i++){
                HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_BYTE, DATA_EEPROM_BASE+addr_offset+32*i, pData);
        }

        if(HAL_ERROR == HAL_FLASHEx_DATAEEPROM_Lock()){
                printf("Flash EEPROM Lock Failed!!!\n");
                return false;
        }

        return true;
}


使用特权

评论回复
16
wakayi|  楼主 | 2019-6-13 14:28 | 只看该作者
bool DATAEEPROM_read(uint16_t addr_offset, uint8_t *pData, uint16_t Size){
        if(Size > DATAEEPROM_MAX_SIZE){
                printf("Size is too long!\r\n");
                return false;
        }
        if(DATA_EEPROM_BASE+addr_offset > DATA_EEPROM_END){
                printf("Flash EEPROM Address Error!!!\n");
                return false;
        }
       
        uint8_t tmp[DATAEEPROM_MAX_SIZE] = {0};
       
        for(uint16_t i=0;i<Size;i++){
                tmp[i] = *(uint32_t*)(DATA_EEPROM_BASE+addr_offset+32*i);
        }
#if 0       
        for(uint16_t i=0;i<Size;i++){
                printf("tmp[%d]:%x\r\n",i,tmp[i]);
        }
#endif       
        memcpy(pData, tmp, Size);
       
        return true;
}


使用特权

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



if(0xaa55aa55 == BKP.RTC_STA){      
...        //显示B画面
}
else
{      
...        //显示A画面
}


使用特权

评论回复
18
wakayi|  楼主 | 2019-6-13 14:29 | 只看该作者
总结
  • 可以选用多种低功耗模式,sleep模式、stop模式、standby模式,其中standby模式功耗最低。
  • 选用standby模式,进入低功耗之后RAM中没有数据了,且只能用特定的且已经配置了的PIN脚来唤醒MCU;
  • standby模式的程序框架为:



2545d01ed5e77557.png (35.88 KB )

2545d01ed5e77557.png

使用特权

评论回复
19
八层楼| | 2019-7-5 09:47 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
20
观海| | 2019-7-5 09:56 | 只看该作者
0.几ua  这也太低了吧

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

85

主题

4084

帖子

1

粉丝