Low Power应用指南

Low Power介绍

本应用指南基于SDK《低功耗使用指南》,提供实际低功耗分析方法,包括漏电分析,待机功耗分析,关机功耗分析,sensor优化分析等。


Low Power分析的准备

LowPower分析的工具

LowPower分析的工具常用工具包括:PPK2KeySight 34465AEMK850x

PPK2

PPK2实物外形:

fishy
  • PPK2的优势

    • 支持uA级功耗测量;

    • 支持电源模式和电流计模式等两种模式测量;

    • 支持IO电平反转功能;

    • 小巧便于携带;

  • PPK2的劣势;

    • 不支持电压和电流同时测量;

    • 单次测量最大时间有限制,不超过 500ms

KeySight 34465A

34465A实物外形:

fishy
  • 34465A的优势

    • 支持uA级功耗测量;

    • 支持电压和电流同步测量;

    • 测量时间不受限制;

  • 34465A的劣势;

    • 外形较大,便携性较差;

    • 仅仅是电流计,不支持供电;

    • 不支持IO电平反转功能;

EMK850x

EMK850x实物外形:

fishy
  • EMK850x的优势

    • 支持uA级功耗测量;

    • 测量时间不受限制;

  • EMK850x的劣势;

    • 不支持电压和电流同时测量;

    • 不支持IO电平反转功能;

低功耗模式的选择

SDK《低功耗使用指南》提到了低功耗模式包括:

PM_SLEEP_MODE_IDLE
PM_SLEEP_MODE_LIGHT
PM_SLEEP_MODE_DEEP
PM_SLEEP_MODE_STANDBY

超低功耗模式包括hibernate 模式和shutdown模式,这两种模式一般用于关机;

HDK56X平台单独实现了一种用STANDBY模式来关机,进入关机时会关闭外设供电,让系统保持在低功耗水平。

52x和56x的低功耗模式如下:

平台

HCPU 睡眠

LCPU睡眠

关机

56x

Standby

Standby

Standby

52x

Deepsleep

Deepsleep

Hibernate

漏电模型

漏电分析是低功耗分析的中一个重要工作,在进行漏电分析前,需要对漏电的来源进行原理上的认识。下面会从PAD的基础模型衍生出漏电的三种模型。

标准PAD模型

fishy

功能描述:

  • DS – driving strength

  • OE – output enable

  • O – output

  • I – input

  • IE – input enable

  • PE – pull enable

  • PS – pull select

组合控制可以实现日常使用的功能;

  • 推挽输出(push-pull)

    OE = 1,O = 0/1
    
  • 开漏输出(open-drain)

    OE = 0/1,O = 0
    

漏电模型1

调整控制如下

OE=1,O=1,PE = 1, PS= 0;

OE=1,O=1表示输出为高;

PE=1,PS=0 表示有下拉电阻;

电流流动如下:

fishy

说明:

电流值:I = Vo/Rpd; Rpd下拉电阻;

pinmux 漏电配置举例:

HAL_PIN_Set(PAD_PA31, GPIO_A31, PIN_PULLDOWN, 1);  //PA31配置为下拉
BSP_GPIO_Set(31, 1, 1); //PA31输出高电平

PA31 输出高电平,有配置了下拉电阻,就会有电流通过下拉电阻持续漏电;

pinmux 配置修正漏电后,如下:

HAL_PIN_Set(PAD_PA31, GPIO_A31, PIN_NOPULL, 1);  //PA31配置无上下拉
BSP_GPIO_Set(31, 1, 1); //PA31输出高电平

漏电模型2

调整控制如下

OE=1,O=0,PE = 1, PS= 1;

OE=1,O=1表示输出为低;

PE=1,PS=1 表示有上拉电阻;

电流流动如下:

fishy

说明:

电流值:I = VDDIO/Rpu; Rpu 上拉电阻;

pinmux 漏电配置举例:

HAL_PIN_Set(PAD_PA31, GPIO_A31, PIN_PULLUP, 1);  //PA31配置为上拉
BSP_GPIO_Set(LCD_VCC_EN, 0, 1); //PA31输出低电平

PA31 配置了上拉,有输出低电平,就会有电流通过上拉电阻持续漏电;

pinmux 配置修正漏电后,如下:

HAL_PIN_Set(PAD_PA31, GPIO_A31, PIN_NOPULL, 1);  //PA31配置无上下拉
BSP_GPIO_Set(LCD_VCC_EN, 0, 1); //PA31输出低电平

漏电模型3

调整控制如下

IE= 1, OE=0,O=0,PE = 0, PS= 0;

如果out 电压处于0~ VDDIO之间的某个电压,会导致input的IO单元的NMOS和PMOS处于半导通状态导致漏电。

电流流动如下:

fishy

说明:

电流值:I=VDD/(Rnmos+Rpmos);

pinmux 漏电配置举例:

HAL_PIN_Set(PAD_PA31, GPIO_A31, PIN_NOPULL, 1);  //PA31配置无上下拉

PA31 配置为nopull,没有上拉也没有下拉,没有调用BSP_GPIO_Set或者 rt_pin_write输出高或低电, IO外部处于浮空状态,没有对应的上下拉固定电平,电平有可能处于0和VDDIO之间,就会导致漏电,漏电大小取决半导通状态的阻抗;

pinmux 配置修正漏电后,如下:

HAL_PIN_Set(PAD_PA31, GPIO_A31, PIN_PULLDOWN, 1);  //PA31配置为下拉

漏电分析

待机时正确的IO配置

正确的IO配置应该是下面的任意一种。

正确的IO配置1: IO口为NC

不用的IO,不要初始化,IO默认会自带上下拉,不需要配置,下图为IO默认上下拉状态

fishy

正确配置2:IO作为输出口,输出高或低电平

一般IO配置为PIN_NOPULL;

1. HAL_PIN_Set(PAD_PA31, GPIO_A31, PIN_NOPULL, 1); //PA31配置无上下拉
2. BSP_GPIO_Set(LCD_VCC_EN, 0, 1); //PA31输出低电平

正确配置3:IO作为输入口,有外部上下拉电阻或者外设能保持稳定的电平

外部有上拉或下拉,或电平确定时,可以配置为:

1. HAL_PIN_Set(PAD_PB45, USART3_TXD, PIN_NOPULL, 0); // USART3 TX
2. HAL_PIN_Set(PAD_PB46, USART3_RXD, PIN_NOPULL, 0); // USART3 RX

或者

1. HAL_PIN_Set(PAD_PB45, USART3_TXD, PIN_PULLUP, 0); // USART3 TX
2. HAL_PIN_Set(PAD_PB46, USART3_RXD, PIN_PULLUP, 0); // USART3 RX

外部有上拉的的电路图示,如下:

fishy

正确配置4:IO作为输入口,外部没有上下拉,也没有外设能保持稳定的电平

外部没有上下拉,且电平不确定时,可以额配置为内部上拉或下拉(适用所有IO)

1. HAL_PIN_Set(PAD_PB45, USART3_TXD, PIN_PULLUP, 0); // USART3 TX
2. HAL_PIN_Set(PAD_PB46, USART3_RXD, PIN_PULLUP, 0); // USART3 RX

或者

1. HAL_PIN_Set(PAD_PB45, USART3_TXD, PIN_PULLDOWN, 0); // USART3 TX
2. HAL_PIN_Set(PAD_PB46, USART3_RXD, PIN_PULLDOWN, 0); // USART3 RX

对于非唤醒源IO,还可以配置为高阻态;

1. HAL_PIN_Set_Analog(PAD_PB45, 0); //设置为高阻
2. HAL_PIN_Set_Analog(PAD_PB46, 0); //设置为高阻

唤醒源IO,不能配置为高阻态原因:

带唤醒功能的IO口,还有唤醒输入另一套输入通道,配置为高阻态,唤醒输入通道还有漏电风险,必须有内部或外部上拉,

唤醒源IO包括:

52x 唤醒源

PA28 ~ PA44

56x 唤醒源

PA50 ~ PA54, PB32 ~ PB36, PBR0~PBR3

常规漏电分析的方法

找出漏电源,是通过检查相关pin的pinmux配置是否符合正确的IO配置:

  • 方法1:通过**“pin starus”** 命令来检查当前pin是否正确配置

    pin status all 列出所有的pin的配置情况

    pin status xx 列出xxpin的配置情况

fishy

pin19, 配置为上拉,实际电平却为低,则会通过上拉电阻漏电,参考《漏电模型2》;

  • 方法2:通过Ozone修改寄存器查看对应电流变化

    当不太确定是哪个pin产生的漏电时,可以通过Ozone 进行debug,手动修改对应pin的寄存器为高阻,查看漏电的变化;

  • 方法3:检查代码的执行时间

    当不太确定是哪个pin产生的漏电时,可以通过Ozone 进行debug,手动修改对应pin的寄存器为高阻,查看漏电的变化;

    功耗和执行时间成正比,通过分析代码执行时间是否合理,来判断功耗的影响;

    常用手段包括:

    • 代码增加tick打印

    • 使用pin作为电平翻转用。(PPK2支持此功能)

    下图中记录了电流波形对应的电平翻转情况,以此分析对应的代码执行电流是否符合预期。

fishy

典型漏电案例说明

  • 案例1:用于电量检测的ADC pin 配置错误

参考原理图如下:

fishy

说明:

当在pinmux 配置成ADC功能时,如果ADC驱动没有打开,就会产生漏电;

一般需要使用ADC的 pin的pinmux用宏包起来;

#ifdef BSP_USING_ADC1
    HAL_PIN_Set_Analog(PAD_PA32, 1);                  // #GPADC_CH5, VBAT_GPADC_CH5, Battery voltage
#else
    HAL_PIN_Set(PAD_PA32, GPIO_A32, PIN_NOPULL, 1);
#endif
  • 案例2:下拉电阻不合适导致的漏电

Audio的电源使能电路如下图:

fishy

说明:

当PA_28_AUDIO_PA_CTRL的置高时,由于下拉电阻只有10k,导致漏电发生。

漏电电流大致:1.8v/10k = 180uA电流;

更改成1M电阻后,电流控制到1.8uA电流;

  • 案例3:用pin时的上电时序导致的漏电问题

PB23 被复用在3个器件: 电源控制芯片,Gsensor、心率;

电路如下图:

fishy

三者都能正常工作的条件:

三个器件必须同时供电正常,否则就会漏电;

Gsensor和心率的I2C上拉的供电必须正常;

  • 案例4:中断pin触发方式和pinmux配置不匹配导致的漏电

心率中断pin的中断触发方式一般是边沿触发;

如果是上升沿触发时,中断常态电平是低,中断发生时拉高,持续一小段高电平后,再拉低;

pinmux的配置方式如下:

如果有外部上拉,则配置成nopull;

如果没有外部上拉,则配置成上拉;

如果是下降沿触发时,中断常态电平是高,中断发生时拉低,持续一小段低电平后,再拉高;

pinmux的配置方式如下:

如果有外部下拉,则配置成nopull;

如果没有外部下拉,则配置成内部下拉;

如果配置相反,则会产生漏电。

例如:上升沿触发时,配置成下拉,则会有漏电产生。

上升沿触发的上拉电阻10k,电源3.3v;\n如果这时配置成下拉,漏电流大小:3.3v/(10k+10k) = 165uA

  • 案例5:HDK525心率reset pin 的pinmux配置时机不得当导致的漏电

HDK525 采用心率vc32s,电路原理如下

fishy

vc32s正常工作时,必须操持reset pin为高;

vc32s 驱动关闭后但供电不关闭,reset pin继续保持为高,也不会漏电;

但当vc32s 驱动关闭后但供电也关闭的时候,reset pin继续保持为高,就会造成大漏电

根本原因:

vc23c 掉电后时,reset pin配置为高,会往器件漏电;

解决方案:

vc23c 掉电和上电时,更新pinmux;

待机低功耗分析

待机低功耗相关配置方法

  • 自动降频的配置

    自动降频功能是指下cpu空闲的时候,会自动降低cpu的频率,当cpu忙碌的时候,把频率升上去,达到降低功耗的目的;

    修改参考下图:

    fishy
  • 修改待机后的MCU频率

    待机后,MCU频率会调整到低速模式,具体运行频率,可以参考下图进行修改:

    fishy
  • RC10K/外置32K的配置 RC10K时钟属于内部时钟,需要周期性校准,会增加功耗;

    32k依赖外部增加硬件晶振,去掉可以降低成本;

    配置方式如下:

    fishy

    选中表示使用RC10K,不选表示使用32k;

  • flash待机的配置

    待机状态,flash会进入睡眠状态,通过在BSP_Power_Up()和BSP_Power_Down()增加flash进入睡眠和退出睡眠接口即可;

    flash进入睡眠参考:

    #if  defined(BSP_USING_NOR_FLASH2)
    #ifdef BSP_QSPI2_DUAL_MODE
        rt_flash_enable_lock(0);
        rt_flash_power_down(0x13000000, 1); //  deep flash 2 bus flash B
        HAL_Delay_us(50);
    #endif
        rt_flash_power_down(0x12000000, 1); //  deep flash 2 bus flash A
        HAL_Delay_us(50);
    #endif
    

    flash退出睡眠参考:

    #if   defined(BSP_USING_NOR_FLASH2)
       rt_flash_power_down(0x12000000, 0); //  deep flash 2 bus flash A
       HAL_Delay_us(50);
    #ifdef BSP_QSPI2_DUAL_MODE
       rt_flash_power_down(0x13000000, 0); //  deep flash 2 bus flash B
       HAL_Delay_us(50);
       rt_flash_enable_lock(1);
    #endif 
    #endif
    
  • psram待机的配置 待机状态,psarm会进入harfsleep状态,通过在BSP_Power_Up()和BSP_Power_Down()增加psram进入和退出harfsleep接口即可;

    psram进入harfsleep状态参考:

    #if defined(BSP_USING_PSRAM1)
        rt_psram_enter_low_power("psram1");
    #endif
    

    psram退出harfsleep状态参考:

    #if defined(BSP_USING_PSRAM1)
        rt_psram_exit_low_power("psram1");
    #endif
    

待机sensor功耗优化

待机后,sensor会周期性的运行,获取sensor的数据,输出健康指标。

优化sensor,一般从以下方面着手:

  • 优化sensor的通讯接口;

  • 调调整sensor相关code和data的存储空间位置;

  • 优化睡眠唤醒;

优化sensor的通讯接口

  1. 选择合适的通讯接口

    sensor 使用的通讯接口包括:I2C,SPI,UART;

    I2C 时钟可选:100k,200k,400k;

    SPI 时钟可选:2M,4M,6M,8M,12M,24M,48M等;

    UART速度:1M,2M,4M,6M等或更低的频率; 三者相比:SPI速度最快,但使用pin最多;UART 速度次之,只占用2个pin,但没有时钟信号;\nI2C速度最慢,有时钟信号,允许挂在多个设备;

    对速度没有要求的场景,优先选I2C;

    对速度有要求但pin不够的场景,可以选UART:

    优先要求速度,pin宽裕的场景,可以选SPI;

    对于功耗优化而言,从sensor读取数据花费的时间越少越好;

  2. I2C接口的优化

    • I2C选择400k时钟后,对应的上拉电阻需要更换成2.2k或4.7k;

    • 对于先写入寄存器地址再读取寄存器内容的方式,可以考虑接口:rt_i2c_mem_reaad()和rt_i2c_mem_write()。可以减少写入寄存器地址和读取寄存器内容之间的间隔;

    效果如下图:

    fishy
    • I2C寄存器数据尽量使用fifo连读方式,对于连续的寄存器尽量一次读完;

    • I2C 可以考虑DMA方式读取;DMA的优势在于不占用CPU资源;

  3. SPI接口的优化

    可以考虑的优化措施包括:

    • 适当提高传输速度,一般选用8M,12M,24M;

    • DMA 通道足够的情况下,使用DMA;

    • buff空间尽量使用RAM空间;

  4. UART接口的优化

    可以考虑的优化措施包括:

    • 适当提高传输速度,一般选用2M,4M,6M;

    • 一般UART RX 使用DMA;

调整sensor相关code和data的存储空间位置

常见存储器件包括:sram,psram,flash,nandflash。

其中:

运行速度对比,sram最快,psram次之,flash最慢;

一般情况下,sensor相关的code 放到psram,data放到sram部分,通过调整sct文件来实现;

举例1:把sensor code 放到psram;

1.   RW_PSRAM_RET PSRAM_DATA_START_ADDR {  ; ZI data, non-cachable, retained
2.     ido_algo*.o (+RO)
3.     sdrv*.o     (+RO)
4. 	*.o         (sys_timer_handle)
5. 	*.o         (ido_algo_activity_result)
6.     *ido_alg_m33_V1_0_42*lib (+RO)
7. 	app_sensor_thread.o (+RO)
8. 	*gsensor*.o         (+RO)
9.   }

使用通配符*,可以很方便的把所有相关的code放到psram。

上段脚本含义:

ido_algo*.o (+RO) ido_algo开头的.c文件的code都放到psram;

*.o (sys_timer_handle) 所有包含sys_timer_handle的.c文件都放到psram;

举例2:把sensor 相关的data放到sram;

data包括声明并且已经赋值的变量 RW,和声明但未赋值的变量ZI;

1. RW_IRAM_RET +0 {    
2.    *ido_alg_m33_V1_0_42*lib (+RW +ZI)
3.    ido_algo*.o (+RW +ZI)
4.   }

上段脚本含义:

ido_alg_m33_V1_0_42lib (+RW +ZI)

表示包含ido_alg_m33_V1_0_42相关的库中的已经赋值的变量和未赋值的变量都放到sram

待机功耗的拆解的方法

待机功耗一般会拆解成最简待机功耗,BT增量功耗,BLE增量功耗,计步待机功耗,心率待机功耗;

拆解的办法有两种:加法拆解,和减法拆解;

加法拆解是指测量最简待机功耗,后逐渐增加功能。通过测量增加功能的总功耗减去最简低价功耗就是对应功能的增量功耗;

减法拆解是指先测量所有功能总功耗,然后把需要测量功耗的功能从剥离;

通过剥离功能前的功耗减去剥离功能后的功耗,得到对应功能的功耗;

功耗拆解相关命令

可以通过以下命令实现单独测单独功能:

fishy

关机低功耗分析

平台支持两种关机方式:Hibernate 关机和Standby关机;

其中:

56x系列	    采用Standby关机;


其他系列	采用Hibernate关机;

主要平台参考功耗如下:

HDK56x Standby关机(uA@3.8v)

HDK561

HDK563

HDK6700

关机功耗

10.76

13.59

13.55

HDK52x Hibernate关机 (uA@3.8v)

HDK521

HDK523

HDK525

关机功耗

2.34

2.2

2.24

关机配置

Standby关机需要配置menuconfig如下:

fishy

选中时,表示standby关机;没选中,表示Hibernate关机;

Standby关机功耗分析

HDK56x standby关机的注意事项:

  1. HDK56x standby关机的时候,HCPU和LCPU都会进入standby 状态;HCPU会关闭psram、flash、LCD、TP等外设供电,关闭大部分唤醒源,核心进入睡眠;LCPU会关闭sensor,蓝牙等,尽可能切断外设供电。

  2. 如果遇到HCPU进入standby成功,而LCPU 进入standby失败的时候,整机功耗会有1mA左右的漏电;

可以考虑以下的原因:

  • 原因1:大核和小核通讯的data_service数据未接收完毕;

    可以通过接口ipc_queue_check_idle()来确认大小核之间dataservice数据传输是否完成;

    如果没有传输完成,需要调整等待时间;

    HCPU调整接口pm_shutdown();

    void pm_shutdown(void)
    {
    #ifdef BSP_PM_STANDBY_SHUTDOWN
       //.........//省略部分代码
    
       //disable all wakeup src
       HAL_HPAON_DisableWakeupSrc(HPAON_WAKEUP_SRC_RTC);
       /****************/
       rt_thread_mdelay(150); //如果遇到dataservice没有传输完成,可以调延时
       /****************/
       HAL_HPAON_DisableWakeupSrc(HPAON_WAKEUP_SRC_LPTIM1);
       HAL_HPAON_DisableWakeupSrc(HPAON_WAKEUP_SRC_LP2HP_IRQ);
    
       MODIFY_REG(hwp_pmuc->LPSYS_SWR, PMUC_LPSYS_SWR_PSW_RET_Msk,
               MAKE_REG_VAL(1, PMUC_LPSYS_SWR_PSW_RET_Msk, PMUC_LPSYS_SWR_PSW_RET_Pos));
       BSP_Standby_PowerDown();
    
       sys_set_is_power_on(false);
       rt_thread_mdelay((RT_TICK_MAX / 2) - 1);
       //.........//省略部分代码
    }
    

    LCPU调整接口power_off_standby_cb,

    static void power_off_standby_cb(void)
    {
       rt_kprintf("%s!
    
    

", func);

#if defined(BF0_LCPU) || defined(SOC_SF32LB52X)
    //mock a service to take over "btn0".
    button_service_mock_in_standby();
#endif

    ipc_send_lcpu_msg_to_hcpu(LCPU_PWR_OFF_RSP, NULL, 0);
    /****************/  
    rt_thread_mdelay(300); /*avoid lcpu data service data not read*/
    /****************/
    //mock a service to take over "SENSORS_APP".
    datac_handle_t lcpu_service = datac_open();
    RT_ASSERT(DATA_CLIENT_INVALID_HANDLE != lcpu_service);
    datac_subscribe(lcpu_service, "SENSORS_APP", standby_service_cb, 0);
    //.........//省略部分代码
}
```
  • 原因2:rt_pm_request(PM_SLEEP_MODE_IDLE) 和rt_pm_release(PM_SLEEP_MODE_IDLE) 没有配对使用,导致睡眠失败;

分析办法:

可以通过打印查看:__pm.modes[PM_SLEEP_IDLE] 来确认。

当__pm.modes[PM_SLEEP_IDLE] 大于0的时候,就表示有rt_pm_release(PM_SLEEP_MODE_IDLE)漏掉了;

  • HCPU和LCPU都进入睡眠了,关机功耗仍然显著高于参考值,可以参考漏电模型检查漏电情况;

重点关注:flash,psram,心率,加速度计等器件掉电后pinmux是否即使更改。避免出现器件已掉电,但IO却配置为上拉的情况;

Hibernate关机功耗分析

  1. Hibernate关机下IO的状态

  • 普通IO(不带唤醒功能)

    在进入hibernate关机后,都为高阻态,内部不漏电,对外为高阻;

  • 带唤醒功能的IO

    比普通IO多一个唤醒输入电路,这部分电路需要在hibernate下唤醒MCU,需要外部或者内部有一个内部上下拉电平,确保唤醒IO不漏电;

    • 55X hibernate关机后,pinmux的上下拉会掉电,唤醒IO内部没有带PMU的上下拉, 只能依赖外部上下拉;

    • 56X,52X hibernate关机后,pinmux的上下拉会掉电,唤醒IO另有带可配置的不掉电PMU上下拉;

  1. Hibernate关机下55X唤醒IO漏电分析

55X hibernate关机后,pinmux的上下拉掉电,唤醒IO内部没有带PMU的上下拉, 只能依赖外部上下拉。

在外部悬空的情况下,依据漏电模型3,唤醒IO内部漏电约为0uA - 200uA漏电不等(不同板子会有差异);

  1. Hibernate关机下52X唤醒IO漏电分析

52X hibernate关机后,唤醒IO带可配置的PMU上下拉。

  • 情况1:

在hibernate关机前,配置为PMU无上下拉,而且外部也没有确定上下拉电平时,依据漏电模型3,唤醒IO内部漏电约为0uA - 200uA漏电不等(不同板子会有差异)

正确配置如下:

pm_shutdown函数中,对唤醒IO,PA28-PA44的统一配置如下

```c
hwp_rtc->PAWK1R = 0x0001ffff;; //PA28-PA44唤醒IO上下拉使能,bit0:PA28,bit1:PA29
hwp_rtc->PAWK2R = 0x0000; //PA28-PA44唤醒IO都配置为下拉,对应bit, 0:下拉,1:上拉 
```
  • 情况2:

在hibernate关机前,配置为PMU上下拉与外部电平相反,也会导致漏电 例如: c     HAL_PIN_Set(PAD_PA24, GPIO_A24, PIN_PULLUP, 1);//唤醒IO PA24配置为PMU内部上拉,导致外设漏电