Low Power应用指南
Low Power介绍
本应用指南基于SDK《低功耗使用指南》,提供实际低功耗分析方法,包括漏电分析,待机功耗分析,关机功耗分析,sensor优化分析等。
Low Power分析的准备
LowPower分析的工具
LowPower分析的工具常用工具包括:PPK2,KeySight 34465A,EMK850x。
PPK2
PPK2实物外形:

PPK2的优势
支持uA级功耗测量;
支持电源模式和电流计模式等两种模式测量;
支持IO电平反转功能;
小巧便于携带;
PPK2的劣势;
不支持电压和电流同时测量;
单次测量最大时间有限制,不超过 500ms
KeySight 34465A
34465A实物外形:

34465A的优势
支持uA级功耗测量;
支持电压和电流同步测量;
测量时间不受限制;
34465A的劣势;
外形较大,便携性较差;
仅仅是电流计,不支持供电;
不支持IO电平反转功能;
EMK850x
EMK850x实物外形:

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模型

功能描述:
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 表示有下拉电阻;
电流流动如下:

说明:
电流值: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 表示有上拉电阻;
电流流动如下:

说明:
电流值: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处于半导通状态导致漏电。
电流流动如下:

说明:
电流值: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默认上下拉状态

正确配置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
外部有上拉的的电路图示,如下:

正确配置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的配置情况

pin19, 配置为上拉,实际电平却为低,则会通过上拉电阻漏电,参考《漏电模型2》;
方法2:通过Ozone修改寄存器查看对应电流变化
当不太确定是哪个pin产生的漏电时,可以通过Ozone 进行debug,手动修改对应pin的寄存器为高阻,查看漏电的变化;
方法3:检查代码的执行时间
当不太确定是哪个pin产生的漏电时,可以通过Ozone 进行debug,手动修改对应pin的寄存器为高阻,查看漏电的变化;
功耗和执行时间成正比,通过分析代码执行时间是否合理,来判断功耗的影响;
常用手段包括:
代码增加tick打印
使用pin作为电平翻转用。(PPK2支持此功能)
下图中记录了电流波形对应的电平翻转情况,以此分析对应的代码执行电流是否符合预期。

典型漏电案例说明
案例1:用于电量检测的ADC pin 配置错误
参考原理图如下:

说明:
当在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的电源使能电路如下图:

说明:
当PA_28_AUDIO_PA_CTRL的置高时,由于下拉电阻只有10k,导致漏电发生。
漏电电流大致:1.8v/10k = 180uA电流;
更改成1M电阻后,电流控制到1.8uA电流;
案例3:用pin时的上电时序导致的漏电问题
PB23 被复用在3个器件: 电源控制芯片,Gsensor、心率;
电路如下图:

三者都能正常工作的条件:
三个器件必须同时供电正常,否则就会漏电;
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,电路原理如下

vc32s正常工作时,必须操持reset pin为高;
vc32s 驱动关闭后但供电不关闭,reset pin继续保持为高,也不会漏电;
但当vc32s 驱动关闭后但供电也关闭的时候,reset pin继续保持为高,就会造成大漏电
根本原因:
vc23c 掉电后时,reset pin配置为高,会往器件漏电;
解决方案:
vc23c 掉电和上电时,更新pinmux;
待机低功耗分析
待机低功耗相关配置方法
自动降频的配置
自动降频功能是指下cpu空闲的时候,会自动降低cpu的频率,当cpu忙碌的时候,把频率升上去,达到降低功耗的目的;
修改参考下图:
修改待机后的MCU频率
待机后,MCU频率会调整到低速模式,具体运行频率,可以参考下图进行修改:
RC10K/外置32K的配置 RC10K时钟属于内部时钟,需要周期性校准,会增加功耗;
32k依赖外部增加硬件晶振,去掉可以降低成本;
配置方式如下:
选中表示使用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的通讯接口
选择合适的通讯接口
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读取数据花费的时间越少越好;
I2C接口的优化
I2C选择400k时钟后,对应的上拉电阻需要更换成2.2k或4.7k;
对于先写入寄存器地址再读取寄存器内容的方式,可以考虑接口:rt_i2c_mem_reaad()和rt_i2c_mem_write()。可以减少写入寄存器地址和读取寄存器内容之间的间隔;
效果如下图:
I2C寄存器数据尽量使用fifo连读方式,对于连续的寄存器尽量一次读完;
I2C 可以考虑DMA方式读取;DMA的优势在于不占用CPU资源;
SPI接口的优化
可以考虑的优化措施包括:
适当提高传输速度,一般选用8M,12M,24M;
DMA 通道足够的情况下,使用DMA;
buff空间尽量使用RAM空间;
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增量功耗,计步待机功耗,心率待机功耗;
拆解的办法有两种:加法拆解,和减法拆解;
加法拆解是指测量最简待机功耗,后逐渐增加功能。通过测量增加功能的总功耗减去最简低价功耗就是对应功能的增量功耗;
减法拆解是指先测量所有功能总功耗,然后把需要测量功耗的功能从剥离;
通过剥离功能前的功耗减去剥离功能后的功耗,得到对应功能的功耗;
功耗拆解相关命令
可以通过以下命令实现单独测单独功能:

关机低功耗分析
平台支持两种关机方式: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如下:

选中时,表示standby关机;没选中,表示Hibernate关机;
Standby关机功耗分析
HDK56x standby关机的注意事项:
HDK56x standby关机的时候,HCPU和LCPU都会进入standby 状态;HCPU会关闭psram、flash、LCD、TP等外设供电,关闭大部分唤醒源,核心进入睡眠;LCPU会关闭sensor,蓝牙等,尽可能切断外设供电。
如果遇到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关机功耗分析
Hibernate关机下IO的状态
普通IO(不带唤醒功能)
在进入hibernate关机后,都为高阻态,内部不漏电,对外为高阻;
带唤醒功能的IO
比普通IO多一个唤醒输入电路,这部分电路需要在hibernate下唤醒MCU,需要外部或者内部有一个内部上下拉电平,确保唤醒IO不漏电;
55X hibernate关机后,pinmux的上下拉会掉电,唤醒IO内部没有带PMU的上下拉, 只能依赖外部上下拉;
56X,52X hibernate关机后,pinmux的上下拉会掉电,唤醒IO另有带可配置的不掉电PMU上下拉;
Hibernate关机下55X唤醒IO漏电分析
55X hibernate关机后,pinmux的上下拉掉电,唤醒IO内部没有带PMU的上下拉, 只能依赖外部上下拉。
在外部悬空的情况下,依据漏电模型3,唤醒IO内部漏电约为0uA - 200uA漏电不等(不同板子会有差异);
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内部上拉,导致外设漏电