低功耗开发指南

1 简介

This article introduces the low-power debugging process based on the SiFli MCU chip on the customer hardware platform。 The SiFli MCU chip is a dual-core Cortex-M33 STAR SoC chip。The big core HCPU operates at a frequency of 0~240MHz, belongs to the HPSYS subsystem, and is suitable for high-performance computing such as graphics, audio, and neural networks;The small core LCPU operates at a frequency of 0~48MHz, belongs to the LPSYS subsystem, and is suitable for tasks such as running Bluetooth, sensor collection and calculation。

  • For low-power development routines, refer to SDK\example\rt_device\pm\project

2 配置低功耗模式

2.1 打开低功耗模式

  1. 在 HCPU 和 LCPU 的工程目录下运行 menuconfig 打开软件配置菜单

  2. Enter SiFli Middleware, select “Enable Low Power Support” to turn on the low power mode support of the middleware,“Enable PM Debug”为调试开关,如图2-1,打开则会输出低功耗相关的日志,日志具体说明参考3.3节;
    alt text

    图 2-1: Middleware Low Power 配置菜单

  3. Enter RTOS → RT-Thread Components → Device Drivers, “Using Power Management Device Drivers” is the low-power service option of the operating system, because the low-power support of the middleware has been enabled, this option is selected by default。“Enable Standby Mode” is used to configure whether the system can enter the STANDBY low-power mode, if selected, it can enter the STANDBY mode, as shown in Figure 2-2, if not selected, it can only enter the LIGHT low-power mode。It should be noted that if the LCPU turns on the STANDBY mode, then the HCPU must also turn on the STANDBY mode。

    alt text

    图 2-2: Device Driver Low Power 配置菜单

  4. After configuration, make sure that the following definitions are included in the project configuration file rtconfig.h:

#define RT_USING_PM 1 //启动PM模块
//#define PM_DEEP_ENABLE 1 //52 MCU建议用DEEP休眠模式
#define PM_STANDBY_ENABLE 1 //55,58,56建议用STANDBY休眠模式
#define BSP_USING_PM 1  //启动PM模块
#define BSP_PM_DEBUG 1 //打印PM[S],[W]的log

2.2 关闭低功耗模式

  1. 在 HCPU 和 LCPU 的工程目录下运行 menuconfig 打开软件配置菜单

  2. Enter SiFli Middleware, uncheck “Enable Low Power Support” to turn off the low power mode support of the middleware

  3. Enter RTOS → RT-Thread Components → Device Drivers, uncheck “Using Power Management Device Drivers” to turn off the low power service of the operating system。

2.3 按键唤醒配置

Refer to SDK\example\rt_device\pm\common routine for configuration method

  1. Standby wake-up configuration (can be used for standby/deep/light wake-up)

The following is an example of the standby wake-up API function at the hal layer, if the IO wake-up needs to handle events, GPIO interrupt needs to be configured:

HAL_HPAON_EnableWakeupSrc(HPAON_WAKEUP_SRC_PIN3, AON_PIN_MODE_LOW); //55x PA80 #WKUP_A3
HAL_LPAON_EnableWakeupSrc(LPAON_WAKEUP_SRC_PIN5, AON_PIN_MODE_NEG_EDGE);//55x PB48 #WKUP_PIN5
//To check if the configuration takes effect, you can refer to the corresponding register in the chip manual:
rt_kprintf("wsr:0x%x,wer:0x%x,\n",hwp_hpsys_aon->WSR,hwp_hpsys_aon->WER); //hcpu
rt_kprintf("wsr:0x%x,wer:0x%x,\n",hwp_lpsys_aon->WSR,hwp_lpsys_aon->WER); //lcpu
  1. 关机唤醒配置(可以用于hibernate唤醒)

For the 55 series MCU, under Hibernate, only the wake-up PIN0-5 of Lcpu has the wake-up function, for details, check the PMUC WER register configuration in the 55 series user manual For MCUs after the 55 series, two wake-up sources PIN0 and PIN1 are allowed to exist simultaneously, each wake-up source can be specified to any Hcpu/Lcpu wake-up PIN, for specific configuration, check the PMUC CR register configuration in the user manual
如下是hal层的关机唤醒API函数示例:

//55x配置方法:
HAL_PMU_EnablePinWakeup(5, AON_PIN_MODE_NEG_EDGE); //55x PB48 #WKUP_PIN5
//To check if the configuration takes effect, you can refer to the corresponding register in the chip manual:
rt_kprintf("CR:0x%x,WER:0x%x\n",hwp_pmuc->CR,hwp_pmuc->WER);
//58x,58x,52x配置方法:
HAL_PMU_SelectWakeupPin(0, HAL_HPAON_QueryWakeupPin(hwp_gpio1,BSP_KEY1_PIN)); //select PA34 to wake_pin0
HAL_PMU_EnablePinWakeup(0, AON_PIN_MODE_HIGH);  //enable wake_pin0 
rt_kprintf("CR:0x%x,WER:0x%x\n",hwp_pmuc->CR,hwp_pmuc->WER);

After Hibernate shutdown, waking up is equivalent to a cold start (but with the PM_HIBERNATE_BOOT flag), unlike Standby wake-up which can resume the original program, the wake-up PIN and level mode are controlled by the PMU register, whether the relevant configuration takes effect can be checked by printing the corresponding PMU’s WER, CR register values;
Note:
If an IO port needs to be woken up during standby and shutdown, both of the above need to be configured;

3 低功耗模式调试方法

3.1 低功耗模式

HPSYS and LPSYS both support the following four low-power modes, but only the IDLE, LIGHT, and STANDBY modes are used in the solution

  • PM_SLEEP_MODE_IDLE:
    CPU 停在 WFI 或 WFE 指令,系统有高速时钟,外设可以工作,所有中断都能 唤醒系统退出 WFI 或 WFI 指令

  • PM_SLEEP_MODE_LIGHT:
    子系统进入 LIGHT 低功耗模式,系统高速时钟关闭,切换到 32K 时钟,外设 停止工作,CPU 与外设均不掉电,可被有限的唤醒源唤醒

  • PM_SLEEP_MODE_DEEP:
    子系统进入 DEEP 低功耗模式,供电切换到 RET_LDO,系统高速时钟关闭,切 换到 32K 时钟,外设停止工作,CPU 与外设均不掉电,可被有限的唤醒源唤醒

  • PM_SLEEP_MODE_STANDBY:
    子系统进入 STANDBY 低功耗模式,供电切换到 RET_LDO,系统高速时钟 关闭,切换到 32K 时钟,CPU 与外设均掉电,可被有限的唤醒源唤醒。HCPU 只有 64KB 的 Retention RAM 保持供电,其上的数据不会丢失,其它 RAM 均会掉电,数据无法保留。LCPU 的 RAM 保持供电,数据可 以保持。

各种低功耗模式的电流见表3-1。
方案中,若存在 PSRAM,HCPU 会将掉电 RAM 上需要保存的数据备份到 PSRAM 中,醒来后从 PSRAM 恢复数 据,如果没有 PSRAM,则将 RAM 上需要保存的数据备份到 64KB 的 Retention RAM 中。
下文如无特别说明,子系统进入睡眠模式是指进入 IDLE 模式以外的低功耗模式,唤醒则指退出 IDLE 模式以外 的低功耗模式。
除了每个子系统提供上述四种低功耗模式外,芯片还提供了两个系统级的关机模式(见表3-2):
• Hibernate 模式:
所有子系统掉电,系统切换到 32K 晶体,可以被 PIN 和 RTC 唤醒,RTC 唤醒时间准确。
软件接口为 HAL_PMU_EnterHibernate。
• Shutdown 模式:
所有子系统掉电,系统切换到 RC10K,可以被 PIN 和 RTC 唤醒,但 RTC 唤醒时间不准 确。软件接口为 HAL_PMU_EnterShutdown。

表 3-1: 低功耗模式

低功耗模式

CPU状态

外设状态

SRAM

唤醒源

唤醒时间

芯片电流 @1.8V

PM_SLEEP_MODE_IDLE

stop

run

可访问

任意中断

<0.5us

LPSYS: 0.2mA~0.8mA HPSYS: 1.2mA~5.5mA

PM_SLEEP_MODE_LIGHT

stop

stop

Inaccessible, fully retained

Wake-up interrupt

30us~100us

LPSYS: 186uA HPSYS: 1155uA

PM_SLEEP_MODE_DEEP

stop

stop

LPSYS:Inaccessible, fully retained HPSYS:不可访问,只保留 64KB

Wake-up interrupt

100us~1ms

LPSYS: 93uA HPSYS: 316uA

PM_SLEEP_MODE_STANDBY

reset

reset

LPSYS:Inaccessible, fully retained HPSYS:不可访问,只保留 64KB

Wake-up interrupt

1ms~2ms

<5uA

表 3-2: 关机模式

低功耗模式

CPU状态

外设状态

SRAM

IO

唤醒源

唤醒时间

芯片电流 @1.8V

Hibernate

reset

reset

Data not retained

High impedance

RTC and PIN

>2ms

600nA

Shutdown

reset

reset

Data not retained

High impedance

RTC and PIN

>2ms

250nA

注:The above current data are for reference only, actual values may increase due to different peripheral enablement and IO settings。stop 表示停止工作,退出低 功耗模式后不需要重新配置即可继续工作;reset 表示停止工作且退出低功耗模式后已被复位,对于 CPU 会从 ROM 开始执行,对于外设需要重新配置才能工作。

3.2 低功耗流程

方案中,只有在熄屏之后,HPSYS 才能进入睡眠模式,亮屏状态下,当 HCPU 不工作时,HPSYS 只能进入 IDLE 模式。只有当 HPSYS 进入睡眠模式后,LPSYS 才能进入睡眠模式,如果 HPSYS 没有睡眠,即使 LCPU 不工作, LPSYS 也只能进入 IDLE 模式(52系列,HCPU和LCPU可以独立休眠的),In the case that HPSYS has been asleep, LPSYS can freely enter and exit the sleep mode without waking up HPSYS。

3.2.1 熄屏

锁屏时间可在设置界面选择,当屏幕无操作超过锁屏时间后屏幕熄灭,在 IDLE 线程中检查睡眠条件,若满足条 件,则 HPSYS 进入睡眠模式,LPSYS 随之也可进入睡眠模式。
alt text
图 3-1: 熄屏流程

3.2.2 HYSYS 唤醒

HPSYS can be woken up by the following events

  • 按键

  • Events from mobile APP(BLE Notification/ Setting/ Incoming call/ Find device/ 推送……)

  • Events from Sensor algorithms(目标达成、久坐提醒、抬腕亮屏、心率异常、历史缓存超出……)

  • 闹钟

  • 低电池电量提醒

  • 充电器插入 After HPSYS is awakened, it can selectively light up the screen. For the following events, there is no need to light up the screen, other events need to wake up the screen:

  1. 来自手机 APP 的 setting 事件

  2. Sensor 的历史缓存超出事件 Take the key press to wake up the screen as an example, the process is shown in Figure 3-2. After the screen lights up, it enters a new round of screen-off judgment process。 来自手机 APP 的 setting 事件触发的唤醒流程如下图3-3所示,当处理完 Setting 请求回到 IDLE 线程后可立即进 入睡眠模式。
    alt text
    图 3-2: 按键亮屏熄屏流程
    alt text
    图 3-3: 收到手机 Setting 事件的唤醒流程

3.2.3 LPSYS 唤醒

LPSYS can be woken up by the following events

  • 按键

  • HPSYS 醒来

  • Sensor data collection timer timeout

  • BLE periodic timer timeout

3.3 日志解读

HCPU 和 LCPU 会通过 console 输出日志,按照2.1节的方法打开低功耗调试开关后,可以在日志中搜索表格中的 关键字分析系统的低功耗流程。 表 3-3: 日志关键字解析

日志

含义

gui_suspend

熄屏

gui_resume

亮屏

[pm]S: mode,gtime

Entering sleep mode, mode indicates low power mode, 2 means LIGHT, 4 means STANDBY。gtime 为当前时间,单位为 32768Hz

[pm]W: gtime

Exit sleep mode,gtime 为当前时间,单位为 32768Hz

[pm]WSR:0xXXXXX

Wake-up reason

The time displayed by gtime is synchronized on both sides of HCPU and LCPU,比如下图3-4中绿色框中的表示系统在 2136602 时刻进入睡 眠,在 2142330 时刻醒来,Wake-up reason为 0x200,由此可知睡眠时长为 sleep_time=(2142330-2136602)/32768=175ms, Wake-up reason为 LPSYS 触发的 mailbox 中断。A certain bit of WSR being 1 indicates that the corresponding source triggered the wake-up, refer to the register table in the corresponding chip manual for the meaning of each bit;
表3-4,表3-5,表3-6为55系列MCU相关配置(数据来源于SF32LB55x-用户手册,4.3 HPSYS_AON 寄存器,4.4 LPSYS_AON 寄存器)。
alt text
图 3-4: 低功耗日志日志示例

表 3-4: 55系列 HPSYS 的 WSR 含义

比特域

含义

[0]

RTC 唤醒

[1]

LPTIM1 唤醒

[2]

PIN0 唤醒

[3]

PIN1 唤醒

[4]

PIN2 唤醒

[5]

PIN3 唤醒

[8]

LPSYS 手动唤醒 HPSYS

[9]

LPSYS 使用 Mailbox 唤醒 HPSYS

表 3-5: 55系列 HPSYS 唤醒 PIN 映射表

唤醒

PIN 含义

PIN0

PA77

PIN1

PA78

PIN2

PA79

PIN3

PA80

表 3-6: 55系列 LPSYS 的 WSR 含义

比特域

含义

[0]

RTC 唤醒

[1]

LPTIM2 唤醒

[2]

LPCOMP1 唤醒

[3]

LPCOMP2 唤醒

[4]

BLE 唤醒

[5]

PIN0 唤醒

[6]

PIN1 唤醒

[7]

PIN2 唤醒

[8]

PIN3 唤醒

[9]

PIN4 唤醒

[10]

PIN5 唤醒

[11]

HPSYS 手动唤醒 LPSYS

[12]

HPSYS 使用 Mailbox 唤醒 LPSYS

表 3-7: 55系列 LPSYS 唤醒 PIN 映射表

唤醒

PIN 含义

PIN0

PB43

PIN1

PB44

PIN2

PB45

PIN3

PB46

PIN4

PB47

PIN5

PB48

3.4 常见问题分析

Since SWD cannot connect after entering sleep mode, UART must be used as the console port to capture logs for problem analysis。

3.4.1 是否进入睡眠模式

If any of the following conditions are met, it is very likely that HPSYS has entered sleep mode

  • SWD cannot connect

  • HCPU console does not respond

  • “s: mode, gtime” appears in the HCPU log

If any of the following conditions are met, it is very likely that LPSYS has entered sleep mode

  • LCPU console does not respond

  • “s: mode, gtime” appears in the LCPU log

It needs to confirm that the finsh shell option in the Command shell has been opened in LCPU。

  • It is also possible to determine the current low-power mode by measuring the voltage of the chip’s power pins。
    当 HPSYS 处于 active,sleep 或 deepsleep 模 式时,LDO1_VOUT 电压保持 1.1V。当 HPSYS 处于 standby 模式时,LDO1_VOUT 电压无法保持,会逐渐下降到 0V。When LPSYS is in active, sleep or deepsleep mode, LDO2_VOUT or BUCK2_VOUT voltage remains at 0.9V。当 LPSYS 处于 standby 模式时,LDO2_VOUT 或 BUCK2_VOUT 电压无法保持,会逐渐下降到 0V。当芯片进入 hibernate 模 式时,LDO1_VOUT,LDO2_VOUT,BUCK2_VOUT 和 VDD_RET 都下降到 0V。
    55系列 低功耗模式下的电源管脚电压,参照图 3-5(数据来源于SF32LB55x-用户手册,4.2.9 判断当前低功耗模式)
    alt text

图 3-5: 55系列 低功耗模式下的电源管脚电压

3.4.2 为什么没有进入睡眠模式

当CPU空闲时进入睡眠模式需要同时满足以下条件:

  • 打开了PM模块

  • CPU已空闲并进入idle线程

  • 未禁止进入睡眠模式

  • 操作系统的定时器超时时间大于睡眠门限

  • 没有唤醒源存在

  • 发送给另外一个核的数据已经被读走 若HCPU或者LCPU出现无法睡眠,可以参考例程SDK\example\rt_device\PM,按以下方法逐个排查,Hcpu和Lcpu排查方法一样

  1. 打开PM模块
    Confirm that the following macros have been generated in rtconfig.h:

#define RT_USING_PM 1
#define BSP_USING_PM 1 //Enable low power mode
#define PM_STANDBY_ENABLE 1 //Enter standby mode for low power consumption # 55,58,56系列Standby hibernation is recommended
//#define PM_DEEP_ENABLE 1 //Enter Deep mode for low power consumption # 52系列Deep hibernation is recommended
#define BSP_PM_DEBUG 1 //Turn on the debug log for low power mode
  1. Ensure that the CPU is idle and enters the idle thread
    You can use the finsh serial command: list_thread to check the status of all threads,Only tshell and tidle should be in the ready state, while others should be in the suspend state,Otherwise, a thread that remains in the ready state will prevent the IDLE thread from running, causing the system to be unable to enter sleep mode。 如下图,我在app_watch_entry()函数中,添加了一条__asm(“B .”);死循环指令,导致app_watch的线程无法进入suspend,导致无法睡眠
    alt text
    图 3-6: list_thread 命令返回的信息

  2. Ensure that entering sleep mode is not prohibited
    在console中发送命令pm_dump,出现如图3-7信息,如果 Idle Mode 的 Counter 大于 0,则表示有模块调 用rt_pm_request(PM_SLEEP_MODE_IDLE)禁止了睡眠,Check whether the code has missed calling rt_pm_release(PM_SLEEP_MODE_IDLE) to lift the sleep inhibition。If it is 0, it means that sleep is not prohibited。
    alt text
    图 3-7: pm_dump 命令返回的信息

  3. Ensure that the timeout time of the operating system timer is greater than the sleep threshold
    Send the command list_timer in the console to display all created timers of the operating system,将 flag 为 activated 定时器的 timeout 值与睡眠门限作比较,If it is less than the sleep threshold, it indicates that the timer causes the inability to enter sleep mode。The unit of the operating system timer timeout is ms。
    alt text
    图 3-8: list_timer 命令返回的信息 见如下配置,HPSYS 的睡眠门限默认为100ms,LPSYS 的睡眠门限为 10ms

RT_WEAK const pm_policy_t pm_policy[] =
{
#ifdef PM_STANDBY_ENABLE
#ifdef SOC_BF0_HCPU
    {100, PM_SLEEP_MODE_STANDBY}, //Hcpu enters standby hibernation when there is no timer wake-up within 100ms
#else
    {10, PM_SLEEP_MODE_STANDBY}, //Lcpu enters standby hibernation when there is no timer wake-up within 10ms
#endif /* SOC_BF0_HCPU */
#elif defined(PM_DEEP_ENABLE)
#ifdef SOC_BF0_HCPU
    {100, PM_SLEEP_MODE_DEEP}, //Hcpu enters Deep hibernation when there is no timer wake-up within 100ms
#else
    {10, PM_SLEEP_MODE_DEEP}, //Lcpu enters Deep hibernation when there is no timer wake-up within 10ms
#endif /* SOC_BF0_HCPU */
#else
#ifdef SOC_BF0_HCPU
    {100, PM_SLEEP_MODE_LIGHT},
#else

见如下代码,If there is a 90ms delay (90ms timer wake-up) in the Hcpu code, Hcpu will never enter hibernation

while(1)
{
    rt_thread_delay(90); //90ms delay
}

Note延时函数区别:
a. HAL layer delay function:(Equivalent to the instruction loop in while, during the delay, it will not switch to other threads)

HAL_Delay(10); /* 延时 10ms */<br>
HAL_Delay_us(10); /* 延时 10us */<br>

b. RTT interface delay function:

rt_thread_delay(100); /* 延时 100ms */<br>

When the RTT interface delay function is executed, it will switch to other threads, such as the ilde thread,
When the sleep threshold is lower than the delay duration, it will enter Standby sleep。
5. Ensure that there are no unprocessed wakeup sources
If there are wakeup sources and they are not cleared, it will not enter sleep mode(因为睡下去也会被唤醒),You can use serial commands to read the WSR registers of Hcpu and Lcpu, Send the command regop read in the console to read the WER and WSR registers,Check if there are any wakeup sources causing the inability to sleep。例如55系列HPSYS 的寄存器地址为 0x40030018 和 0x4003001C,LPSYS 的寄存器地址为 0x40070018 和 0x4007001C。

regop unlock 0000
regop read 4007001c 1
regop read 4003001c 1

You can also connect to debuggers like Jlink/SifliUsartServer to read the register values,You can also obtain the WSR value by printing logs,Refer to the corresponding chip manual for the WSR register to compare specific wakeup sources.

rt_kprintf("wsr:0x%x,wer:0x%x,\n",hwp_hpsys_aon->WSR,hwp_hpsys_aon->WER); //hcpu
rt_kprintf("wsr:0x%x,wer:0x%x,\n",hwp_lpsys_aon->WSR,hwp_lpsys_aon->WER); //lcpu

A common issue is incorrect pin level status for wakeup, for example, setting low-level wakeup but the pin level is always low
6. Ensure that the data for another core has been read
You can use Ozone connection, dump memory and then view with trace32 or print logs,查看看ipc_ctx变量中每一个queues为active的tx_buffer,To see if there is any data that has not been taken away,如图3-9,read_idx_mirror and write_idx_mirror are normally equal or empty,如果不相等, 即有数据没有被取走, 会导致无法进入睡眠,如下非空数据没取走不能睡眠情况:
alt text
图 3-9: read_idx_mirror和write_idx_mirror非空的情形
如图3-10为数据为空的情形

alt text
图 3-10: read_idx_mirror和write_idx_mirror空的情形
下面是log打印出每个active为1的read_idx_mirror和write_idx_mirror内容

for(i=0;i<IPC_LOGICAL_QUEUE_NUM;i++)
{
    if(ipc_ctx.queues[i].active == true)
    {
        if(ipc_ctx.queues[i].rx_ring_buffer != NULL)
        {
            if(ipc_ctx.queues[i].tx_ring_buffer != NULL)
            {
                LOG_I("ipc_ctx.queues[%d].tx read_idx_mirror=0x%x,write_idx_mirror=0x%x\n",i,ipc_ctx.queues[i].tx_ring_buffer->read_idx_mirror,ipc_ctx.queues[i].tx_ring_buffer->write_idx_mirror);
            }
        }
    }
}

如图3-11,An example where Hcpu does not enter sleep mode because Lcpu did not open the data service, missing the channel with qid=1, so the data sent by Hcpu was not taken by Lcpu
alt text

4 功耗优化方法

4.1 待机漏电分析

If both HPSYS and LPSYS have entered sleep mode, the focus of overall power consumption optimization unfolds from the following three points:
1,Screen, peripheral sensors, charging IC, these removable components should be removed first to check the minimum system current;
2,Incorrect IO level configuration in software creates voltage difference, leading to leakage,输入IO没有上下拉导致浮空漏电;
3,芯片内部psram/flash和外部nand/flash/emmc没有进入休眠;
如果硬件可以拆解电流,可以具体用电流表查看是哪一路供电的漏电,VSYS,VLDO2,VLDO3,VDD_SIP,VDDIOA?
这样可以缩少查的范围

4.1.1 外设漏电

1) The board-level device is not powered off
2) The board-level device has lost power, but incorrect chip pin settings cause current to flow back from the chip pins into the board-level device
针对 2),To avoid the chip pin connected to the powered-off device from outputting high or enabling the pull-up resistor。 According to the aforementioned analysis of the causes of leakage, the configuration methods for commonly used peripheral pins in working and sleep states can be found in Table 4-1,When the external circuit does not lose power, since the circuit state has not changed, there is no need to change the pin configuration even when entering sleep mode,It is only necessary to modify the settings of the relevant pins when the external circuit loses power,因此If the external circuit has already lost power without entering sleep mode, the pin settings should be modified immediately to reduce power consumption,类似的,If the external circuit is still in a power-off state after waking up from sleep, because the pin settings will revert to default values due to power loss, they need to be modified again to the power-off state settings。
表 4-1: 管脚推荐设置

外设

管脚

方向

工作状态

睡眠(外部电路不掉电)

睡眠(外部电路掉电)

PSRAM

PSRAM_CLK

O

数字输出

数字输出

GPIO 模式输出低

PSRAM

PSRAM_CLKB

O

数字输出

数字输出

GPIO 模式输出低

PSRAM

PSRAM_CS

O

数字输出

数字输出

GPIO 模式输出低

PSRAM

PSRAM_DM0

O

数字输出

数字输出

GPIO 模式输出低

PSRAM

PSRAM_DM1

O

数字输出

数字输出

GPIO 模式输出低

PSRAM

PSRAM_DQS0

I/O

数字输入下拉

数字输入下拉

数字输入下拉

PSRAM

PSRAM_DQS1

I/O

数字输入下拉

数字输入下拉

数字输入下拉

PSRAM

PSRAM_DQx

I/O

数字输入下拉

数字输入下拉

数字输入下拉

QSPI

QSPIx_CLK

O

数字输出

数字输出

GPIO 模式输出低

QSPI

QSPIx_CS

O

数字输出

数字输出

GPIO 模式输出低

QSPI

QSPIx_DIO0

I/O

数字输入下拉

数字输入下拉

数字输入下拉

QSPI

QSPIx_DIO1

I/O

数字输入下拉

数字输入下拉

数字输入下拉

QSPI

QSPIx_DIO2

I/O

数字输入上拉

数字输入上拉

数字输入下拉

QSPI

QSPIx_DIO3

I/O

数字输入上拉

数字输入上拉

数字输入下拉

QSPI

QSPIx_DIO4

I/O

数字输入下拉

数字输入下拉

数字输入下拉

QSPI

QSPIx_DIO5

I/O

数字输入下拉

数字输入下拉

数字输入下拉

QSPI

QSPIx_DIO6

I/O

数字输入上拉

数字输入上拉

数字输入下拉

QSPI

QSPIx_DIO7

I/O

数字输入上拉

数字输入上拉

数字输入下拉

USART

USARTx_RXD

I

数字输入上拉

数字输入上拉

数字输入下拉

USART

USARTx_TXD

O

数字输出

数字输出

数字输出

USART

USARTx_CTS

I

数字输入上拉

数字输入上拉

数字输入下拉

USART

USARTx_RTS

O

数字输出

数字输出

数字输出

I2C

I2Cx_SCL

I/O

数字输入

数字输入

数字输入下拉

I2C

I2Cx_SDA

I/O

数字输入

数字输入

数字输入下拉

SPI Master

SPIx_CLK

O

数字输出

数字输出

GPIO 模式输出低

SPI Master

SPIx_CS

O

数字输出

数字输出

GPIO 模式输出低

SPI Master

SPIx_DI

I

数字输入下拉

数字输入下拉

数字输入下拉

SPI Master

SPIx_DO

O

数字输出

数字输出

GPIO 模式输出低

SPI Master

SPIx_DIO

I/O

数字输入下拉

数字输入下拉

数字输入下拉

LCDC SPI

LCDCx_SPI_CS

O

数字输出

数字输出

GPIO模式输入下拉

LCDC SPI

LCDCx_SPI_CLK

O

数字输出

数字输出

GPIO 模式输入下拉

LCDC SPI

LCDCx_SPI_DIO0

I/O

数字输入下拉

数字输入下拉

GPIO 模式输入下拉

LCDC SPI

LCDCx_SPI_DIO1

O

数字输出

数字输出

GPIO 模式输入下拉

LCDC SPI

LCDCx_SPI_DIO2

O

数字输出

数字输出

GPIO 模式输入下拉

LCDC SPI

LCDCx_SPI_DIO3

O

数字输出

数字输出

GPIO 模式输入下拉

LCDC SPI

LCDCx_SPI_RSTB

O

数字输出

数字输出

GPIO 输出低

LCDC SPI

LCDCx_SPI_TE

I

数字输入

数字输入

GPIO 模式输入下拉

SDIO

SD_CLK

O

数字输出

数字输出

GPIO 模式输出低

SDIO

SD_CMD

I/O

数字输入上拉

数字输入上拉

数字输入下拉

SDIO

SD_DIOx

I/O

数字输入上拉

数字输入上拉

数字输入下拉

I2S

I2S1_BCK

O

数字输出

数字输出

GPIO 模式输出低

I2S

I2S1_LRCK

O

数字输出

数字输出

GPIO 模式输出低

I2S

I2S1_SDI

I

数字输入下拉

数字输入下拉

数字输入下拉

I2S

I2S2_BCK

O

数字输出

数字输出

GPIO 模式输出低

I2S

I2S2_LRCK

O

数字输出

数字输出

GPIO 模式输出低

I2S

I2S2_SDI

I

数字输入下拉

数字输入下拉

数字输入下拉

I2S

I2S2_SDO

O

数字输出

数字输出

GPIO 模式输出低

PDM

PDM_CLK

O

数字输出

数字输出

GPIO 模式输出低

PDM

PDM_DATA

I

数字输入下拉

数字输入下拉

数字输入下拉

GPTIM输出

GPTIMx_CHx

O

数字输出

数字输出

GPIO 模式输出低

GPTIM输入

GPTIMx_CHx

I

数字输入下拉

数字输入下拉

数字输入下拉

GPTIM

GPTIMx_ETR

I

数字输入下拉

数字输入下拉

数字输入下拉

GPIO Input

GPIO

I

数字输入

数字输入

GPIO 输出低或者数字输入下拉

GPIO Output

GPIO

O

数字输出

数字输出

GPIO 模式输出低

4.1.2 芯片IO内部漏电

在FAQ常见问题解答的 8.7 Standby待机和Standby关机IO内部常见的漏电模型8.7 Standby待机和Standby关机IO内部常见的漏电模型中有详细介绍;
可以归纳为:
1) The input pin is floating (the power-off of the remote device is equivalent to the pin floating), resulting in an uncertain level
2) The IO output level does not match the internal and external pull-up/pull-down resistors
如图 4-1: 管脚内部结构图,功能描述如下:

  • DS - driving strength

  • OE - output enable

  • O – output

  • I – input

  • IE – input enable

  • PE – pull enable

  • PS – pull select 组合控制可以实现日常使用的功能;
    Push-pull output

  • OE = 1,O = 0/1 Open-drain output

  • OE = 0/1,O = 0
    图 4-1: 管脚内部结构图

    alt text
    Note:
    For the 55 series, the PA01 port of USB has an internal default 18K ohm pull-down resistor, which will cause leakage when outputting high or connecting to a high external voltage,The handling method can be found in section [1.6 Risk of Leakage for PA01/PA03 Multiplexing USB in 55 Series MCU] of the FAQ(…/…/faq/mcu/gpio.md/#16-55系列mcu复用usb的pa01pa03漏电风险)

4.1.3 芯片内外部存储芯片漏电

  1. The method for PSRAM to enter and exit Half_sleep

void BSP_Power_Up(bool is_deep_sleep)
{
#ifdef SOC_BF0_HCPU
    if (!is_deep_sleep)
    {
#if defined(BSP_USING_PSRAM1)
        rt_psram_exit_low_power("psram1"); //退出half_sleep
#endif
    }
    //以下省略
}
void BSP_IO_Power_Down(int coreid, bool is_deep_sleep)
{
#ifdef SOC_BF0_HCPU
    if (coreid == CORE_ID_HCPU)
    {
#if defined(BSP_USING_PSRAM1)
        rt_psram_enter_low_power("psram1");  //进入half_sleep
#endif
    }
#else
    //以下省略
#endif
}
  1. Flash掉电和进出deep_sleep的方法
    The following code demonstrates the method for nor flash power-down and entering/exiting deep sleep:

HAL_RAM_RET_CODE_SECT(BSP_PowerDownCustom, void BSP_PowerDownCustom(int coreid, bool is_deep_sleep))
{
#ifdef SOC_BF0_HCPU
#ifdef BSP_USING_NOR_FLASH2
    HAL_PMU_ConfigPeriLdo(PMU_PERI_LDO2_3V3, false, true); //The method to turn off nor flash power supply

    HAL_PIN_Set(PAD_PA16, GPIO_A16, PIN_PULLDOWN, 1); //After turning off the power supply, the IO of flash needs to be changed to pull-down
    HAL_PIN_Set(PAD_PA12, GPIO_A12, PIN_PULLDOWN, 1);
    HAL_PIN_Set(PAD_PA15, GPIO_A15, PIN_PULLDOWN, 1);
    HAL_PIN_Set(PAD_PA13, GPIO_A13, PIN_PULLDOWN, 1);
    HAL_PIN_Set(PAD_PA14, GPIO_A14, PIN_PULLDOWN, 1);
    HAL_PIN_Set(PAD_PA17, GPIO_A17, PIN_PULLDOWN, 1);

    HAL_PIN_Set(PAD_PA35, GPIO_A35, PIN_PULLDOWN, 1);
    HAL_PIN_Set(PAD_PA36, GPIO_A36, PIN_PULLDOWN, 1);
#elif defined(BSP_USING_NOR_FLASH1)
    FLASH_HandleTypeDef hflash; 
    hflash.Instance = FLASH1;
    HAL_FLASH_DEEP_PWRDOWN(&hflash); //The method for nor flash to enter deep sleep, in this way, the status of IO does not need to be modified
    HAL_Delay_us(3);
#endif /* BSP_USING_NOR_FLASH2 */
#else
    {
        ;
    }
#endif

HAL_RAM_RET_CODE_SECT(BSP_PowerUpCustom, void BSP_PowerUpCustom(bool is_deep_sleep))
{
#ifdef SOC_BF0_HCPU
    if (!is_deep_sleep)
    {
#ifdef BSP_USING_NOR_FLASH2
        HAL_PIN_Set(PAD_PA16, MPI2_CLK,  PIN_NOPULL,   1); //Before turning on nor flash power supply, configure IO to working state first
        HAL_PIN_Set(PAD_PA12, MPI2_CS,   PIN_NOPULL,   1);
        HAL_PIN_Set(PAD_PA15, MPI2_DIO0, PIN_PULLDOWN, 1);
        HAL_PIN_Set(PAD_PA13, MPI2_DIO1, PIN_PULLDOWN, 1);
        HAL_PIN_Set(PAD_PA14, MPI2_DIO2, PIN_PULLUP,   1);
        HAL_PIN_Set(PAD_PA17, MPI2_DIO3, PIN_PULLUP, 1);

        HAL_PIN_Set(PAD_PA35, GPIO_A35, PIN_PULLUP, 1);
        HAL_PIN_Set(PAD_PA36, GPIO_A36, PIN_PULLUP, 1);

        HAL_PMU_ConfigPeriLdo(PMU_PERI_LDO2_3V3, true, true); // Turn on nor flash power supply

        BSP_Flash_hw2_init(); //After power-off, it is necessary to reinitialize nor flash
#elif defined(BSP_USING_NOR_FLASH1)
        FLASH_HandleTypeDef hflash; //The method for nor flash to exit deep sleep, in this way, the status of IO does not need to be modified
        hflash.Instance = FLASH1;
        HAL_FLASH_RELEASE_DPD(&hflash);
        HAL_Delay_us(8); //A certain delay is required after exiting deep sleep, the specific delay needs to check the flash chip manual
#endif /* BSP_USING_NOR_FLASH2 */
    }
    else if (PM_STANDBY_BOOT == SystemPowerOnModeGet())
    {
    }
#elif defined(SOC_BF0_LCPU)
    {
        ;
    }
#endif
}

Note:
For the case where the XIP code runs on nor flash, the code for operating nor flash into sleep needs to be declared to run inside RAM HAL_RAM_RET_CODE_SECT

4.2 代码实现

管脚的配置代码实现在开发板的 pinmux.c 和 drv_io.c(55系列),bsp_power.c(58,56,52系列) 文件中,需要根据开发板的 IO 功能定义与硬件设计实现 BSP_PIN_InitBSP_Power_UpBSP_IO_Power_Down 等接口。

4.2.1 工作状态管脚设置

BSP_PIN_Init 在冷启动和 STANDBY 醒来都会被执行一次,可以在 BSP_PIN_Init 中设定工作状态下每个管脚的 功能和输入输出模式。
Use the function HAL_PIN_Set to select the function and pull-up/pull-down attributes of the pin. For example, the following sample code configures the PB46 pin as USART3_RX function and sets it to digital input pull-up mode.

HAL_PIN_Set (PAD_PB46, USART3_RXD, PIN_PULLUP, 0);

对于用于输出的IO,如果配置了PIN_NOPULL模式,而又没有进行GPIO输出,就会出现输入口悬空漏电的情况,

HAL_PIN_Set(PAD_PA35, GPIO_A35, PIN_NOPULL, 1);

如上:If only configure PA35 as IO, PIN_NOPULL, and do not configure GPIO output high or low afterwards, otherwise the GPIO pin defaults to input mode, there will be a situation of floating input port leakage. It is also necessary to call the GPIO interface to output a determined level. The HAL layer function BSP_GPIO_Set can set the GPIO output level, and after RTOS starts, the driver layer can also output high or low.
If you want to restore to input mode, you can call HAL_GPIO_DeInit.

4.2.2 Pin settings for sleep state

在drv_io.c(55系列),bsp_power.c(58,56,52系列) 文件中用户可以实现以下几个虚函数,用于在进出睡眠模式时动态切换管脚设置,优化整机功耗。

表 4-2: 睡眠状态的管脚设置 API

函数名

说明

BSP_IO_Power_Down

Executed before entering sleep

BSP_Power_Up

Executed after waking up (for STANDBY mode wakeup, executed after BSP_PIN_Init)

BSP_TP_PowerDown

Executed after screen off

BSP_TP_PowerUp

Executed before lighting the screen

BSP_LCD_PowerDown

Executed after screen off

BSP_LCD_PowerUp

Executed before lighting the screen


Note:
52系列采用Deep休眠,流程会不太一样,参考休眠流程52系列章节

如果板级器件的掉电和上电控制都伴随睡眠进行,可以在 BSP_IO_Power_Down 中将板级器件断电并修改相应的 管脚设置,反向操作则在 BSP_Power_Up 中完成。但这种方法的缺点是控制不够精细,比如熄屏后,可能过一段 时间 HPSYS 才会进入睡眠,在此之前如果仍旧给 LCD 供电的话就会增加耗电,或者当 HPSYS 被唤醒执行一段 时间任务但又不需要亮屏时,如果在 BSP_Power_Up 中就打开屏幕的供电,也会增加耗电。 为此,用户可以在 BSP_IO_Power_Down 和 BSP_Power_Up 中实现更复杂的控制逻辑。以屏幕与触控为例,将屏幕 与触控的掉电处理放在 BSP_TP_PowerDown 和 BSP_LCD_PowerDown 中,这样一旦熄屏后屏幕与触控芯片即可 马上断电,而在 BSP_Power_Up 里需要再次调用 BSP_TP_PowerDown 和 BSP_LCD_PowerDown,这样即使 HPSYS 被唤醒,也可以将管脚的设置恢复到掉电状态,如果满足了亮屏条件,系统会在亮屏前调用 BSP_TP_PowerUp 和 BSP_LCD_PowerUp 恢复屏幕与触控的供电与工作状态下的管脚设置。

4.3 休眠流程

56系列

  • Hcpu sleep and wake up
    When hcpu enters the idle thread and determines whether the sleep conditions are met, the following process will be followed for sleep and wake-up
    rt_thread_idle_entry->rt_system_power_manager->_pm_enter_sleep->'pm->ops->sleep(pm, mode);->sifli_sleep -> log 打印[pm]S:4,11620140 -> RT_DEVICE_CTRL_SUSPEND 设备挂起 ->  sifli_standby_handler ->BSP_IO_Power_Down-> 汇编 WFI 进入 standby-> 定时器或者IO唤醒 -> 函数 SystemInitFromStandby -> HAL_Init -> BSP_IO_Init-> restore_context-> PC 指针设置到 sifli_standby_handler 函数 WFI 后指令继续运行 -> BSP_Power_Up-> 执行 RTT 设备 RT_DEVICE_CTRL_RESUME 设备恢复函数 -> log 打印[pm]W:11620520 -> log 打印[pm]WSR:0x80

  • LCPU休眠唤醒
    The Lcpu sleep and wake-up process is basically the same as the hcpu standby process,差异点:
    sifli_standby_handler-> sifli_standby_handler_core->休眠时IO配置函数BSP_IO_Power_Down->内存休眠函数soc_power_down-> 汇编 WFI 进入 standby->定时器或者IO唤醒 -> 函数 SystemPowerOnModeInit ->SystemPowerOnInitLCPU-> HAL_Init-> BSP_IO_Init-> restore_context-> 设置到 WFI 指令后继续执行  -> 内存退出休眠函数soc_power_up-> IO休眠后配置函数BSP_Power_Up-> 执行 RTT 设备 RT_DEVICE_CTRL_RESUME 设备恢复函数 -> log 打印[pm]W:11620520 -> log 打印[pm]WSR:0x80

55系列

  • The 55 series has the same standby process as the 56 series, with the difference being in the wake-up functions
    定时器或者IO唤醒 -> 函数SystemPowerOnModeInit -> HAL_Init -> BSP_IO_Init->restore_context-> PC 指针设置到 sifli_standby_handler 函数 WFI 后指令继续运行 -> BSP_Power_Up-> 执行 RTT 设备 RT_DEVICE_CTRL_RESUME 设备恢复函数 -> log 打印[pm]W:11620520 -> log 打印[pm]WSR:0x80

  • Lcpu唤醒流程56系列一样

52系列

  • 52系列跟56系列的待机流程差异的点在进的是sifli_deep_handler();待机函数,并且少了外设的SUSPEND/RESUME和恢复现场过程,睡眠唤醒更快
    sifli_sleep -> log 打印[pm]S:3,11620140 -> sifli_deep_handler ->BSP_IO_Power_Down-> 汇编 WFI 进入 deep-> 定时器或者IO唤醒 ->  WFI 后指令继续运行 -> BSP_Power_Up->  log 打印 [pm]W:11620520 -> log 打印[pm]WSR:0x80

  • The Lcpu of the 52 series does not allow code modification, so this part does not need to be considered

4.4 Hibernate关机漏电分析

4.4.1 Hibernate关机流程

  • 进入Hibernate
    进入Hibernate流程相对简单,调用HAL_PMU_EnterHibernate();函数,芯片在休眠前,都需要配置好Hibernate后PMU的唤醒PIN和唤醒电平,The 55 series MCU does not require any further processing,For the 56, 56 series MCU, due to an additional set of PMU pull-up/pull-down systems effective in Hibernate for the wake-up PIN to prevent leakage, the function HAL_PIN_Set can be used to configure the pull-up/pull-down of the wake-up PIN,Since the 52 series MCU has three built-in LDOs, you need to check your hardware connections to consider whether to configure shutdown via the function HAL_PMU_ConfigPeriLdo

  • Hibernate唤醒
    After pressing the wake-up PIN to wake up from Hibernate, you can determine whether (PM_HIBERNATE_BOOT == SystemPowerOnModeGet()) is hibernate boot and the duration of the key press to decide whether to boot up。

4.4.2 Hibernate关机配置

  • Enter Hibernate hibernation shutdown mode
    调用函数HAL_PMU_EnterHibernate();,在进入Hibernate前,配置好PMU的唤醒PIN和唤醒电平,确保Enter Hibernate hibernation shutdown mode后能够被唤醒,The wake-up PIN of the 55 series MCU is in a floating input state under hibernate. To prevent floating leakage, external circuits need to provide pull-up/pull-down states; The 58, 56, 52 series MCUs, in order to solve the problem of the 55 series MCU requiring additional external pull-up/pull-down resistors when entering Hibernate shutdown mode, have an additional set of PMU pull-up/pull-down systems effective under Hibernate for the wake-up PIN(对应软件寄存器为:
    hwp_rtc->PAWK1R,hwp_rtc->PAWK2R),It is recommended to use the function HAL_PIN_Set to configure the pull-up/pull-down of the wake-up PIN, 52系列MCU由于内置了3个LDO(软件对应为:PMU_PERI_LDO_1V8PMU_PERI_LDO2_3V3PMU_PERI_LDO3_3V3),需要查看你的硬件连接,来考虑是否通过函数HAL_PMU_ConfigPeriLdo配置关闭。
    The hwp_pmuc->WKUP_CNT register can be configured for how long the external signal needs to last to wake up after hibernate(只限58,56,52系列MCU);
    The following code is the configuration before the 52 series MCU enters Hibernate:

rt_kprintf("SF32LB52X entry_hibernate\n");
HAL_PMU_SelectWakeupPin(0, HAL_HPAON_QueryWakeupPin(hwp_gpio1,BSP_KEY1_PIN)); //select PA34 to wake_pin0
HAL_PMU_EnablePinWakeup(0, AON_PIN_MODE_HIGH);  //enable wake_pin0 
hwp_pmuc->WKUP_CNT = 0x50005;    //31-16bit:config PIN1 wake CNT , 15-0bit:PIN0 wake CNT
rt_kprintf("SF32LB52X CR:0x%x,WER:0x%x\n",hwp_pmuc->CR,hwp_pmuc->WER);
HAL_PIN_Set(PAD_PA24, GPIO_A24, PIN_PULLDOWN, 1); //#WKUP_PIN0
HAL_PIN_Set(PAD_PA25, GPIO_A25, PIN_PULLDOWN, 1); //#WKUP_PIN1
HAL_PIN_Set(PAD_PA26, GPIO_A26, PIN_PULLDOWN, 1); //#WKUP_PIN2
HAL_PIN_Set(PAD_PA27, GPIO_A27, PIN_PULLDOWN, 1); //#WKUP_PIN3

HAL_PIN_Set(PAD_PA34, GPIO_A34, PIN_PULLDOWN, 1); //#WKUP_PIN10
HAL_PIN_Set(PAD_PA35, GPIO_A35, PIN_PULLDOWN, 1); //#WKUP_PIN11
HAL_PIN_Set(PAD_PA36, GPIO_A36, PIN_PULLDOWN, 1); //#WKUP_PIN12
HAL_PIN_Set(PAD_PA37, GPIO_A37, PIN_PULLDOWN, 1); //#WKUP_PIN13
HAL_PIN_Set(PAD_PA38, GPIO_A38, PIN_PULLDOWN, 1); //#WKUP_PIN14
HAL_PIN_Set(PAD_PA39, GPIO_A39, PIN_PULLDOWN, 1); //#WKUP_PIN15
HAL_PIN_Set(PAD_PA40, GPIO_A40, PIN_PULLDOWN, 1); //#WKUP_PIN16
HAL_PIN_Set(PAD_PA41, GPIO_A41, PIN_PULLDOWN, 1); //#WKUP_PIN17
HAL_PIN_Set(PAD_PA42, GPIO_A42, PIN_PULLDOWN, 1); //#WKUP_PIN18
HAL_PIN_Set(PAD_PA43, GPIO_A43, PIN_PULLDOWN, 1); //#WKUP_PIN19
HAL_PIN_Set(PAD_PA44, GPIO_A44, PIN_PULLDOWN, 1); //#WKUP_PIN20

rt_hw_interrupt_disable();
HAL_PMU_ConfigPeriLdo(PMU_PERI_LDO2_3V3, false, false); 
HAL_PMU_ConfigPeriLdo(PMU_PERI_LDO3_3V3, false, false);
HAL_PMU_ConfigPeriLdo(PMU_PERI_LDO_1V8, false, false);
HAL_PMU_EnterHibernate();


Note:

  • For the 55 series MCU, since each wake-up pin can be enabled individually, configuring the Hibernate wake-up source only requires calling the function HAL_PMU_EnablePinWakeup to enable the corresponding wake-up pin;

  • For the 58, 56, and 52 series MCU, only two wake-up source pins (pin0 and pin1) are allowed to exist simultaneously. An additional step is required here: call the function HAL_PMU_SelectWakeupPin to select which specific wake-up pin corresponds to pin0 and pin1. Refer to hwp_pmuc->CR for the corresponding register configuration;

  • The #WKUP_PIN4-9 (PA28-PA33) of the 52 series MCU have been repurposed as general IO ports due to internal multiplexing with ADC, and their wake-up port functionality has been removed,The handling method is shown in the red box in the figure below, where the external IO is disconnected and internally pulled low(No processing is needed under Hibernate mode to avoid leakage),However, directly manipulating the registers hwp_rtc->PAWK1R, hwp_rtc->PAWK2R to pull up may cause leakage。
    alt text

  • Hibernate Wake-up Judgment
    After pressing the wake-up PIN to wake up from Hibernate, you can determine whether it is a hibernate boot by checking if(PM_HIBERNATE_BOOT == SystemPowerOnModeGet()) and judging the duration of the key press to decide whether to power on