HiSpark编程指南

- 调测资料
  - SDK Sample使用指南
    - 前言
    - 概述
    - Sample框架
    - 外设 Sample
    - SLE UART Sample
    - SLE UART DMA Sample
    - SLE Mouse Sample
    - SLE amic vdt with dongle
    - SLE microphone
    - SLE measure dis
    - BLE Lowpower Sample
    - BLE UART Sample
    - BLE Keyboard Sample
    - BLE SLE TAG Sample
    - BLE Mouse Sample
    - USB Keyboard Sample
    - USB Mouse Sample
    - USB AMIC VDT Sample
    - RCU
    - 多连接
    - air mouse
    - SLE MOUSE with Dongle
    - SLE OTA dongle
    - game mouse
    - BLE UUID
    - 缩略语
  - SDK二次开发网络安全注意事项
    - 前言
    - 产品安全解决方案
    - 结论
  - SDK开发环境搭建用户指南
    - 前言
    - 开发环境搭建
    - 编译SDK
    - 新建APP
  - 内存维测指导书
    - 前言
    - 简介
    - 内存维测功能
  - 射频AT测试指南
    - 前言
    - 射频测试AT指令
    - AT指令组包示例
    - 注意事项
  - 维测指导书
    - 前言
    - 概述
    - 日志说明
    - 日志分析
    - 问题定位
    - 典型案例
    - 常见问题FAQ
- 软件资料
  - AT命令使用指南
    - 前言
    - 指令说明
    - 通用AT指令
    - BT业务AT指令
    - 新增AT指令方法
  - DFU升级APK开发指南
    - 前言
    - 功能特性
    - 系统框架
    - 工程文件部署
    - 界面实现
    - 升级界面Fragment实现
    - 关于界面Fragment实现
    - 应用清单AndroidManifest
  - DFX软件开发指南
    - 前言
    - DIAG维测功能
    - 死机诊断
    - Dump解析
  - EFUSE使用指南
    - 前言
    - 概述
    - 使用软件接口读写EFUSE
    - 使用BurnTool烧写EFUSE
  - NFC TAG软件开发指导书
    - 前言
    - 概述
    - 开发指导
  - NV存储用户指南
    - 前言
    - NV简介
    - NV编译预置
    - NV API指南
    - 定制化NV结构使用介绍
    - 通过NV自定义传输数据最大长度
  - Release notes
    - 1.0.18版本描述文件
    - 1.0.17版本描述文件
    - 1.0.16版本描述文件
  - SDK开发指南
    - 前言
    - 概述
    - 系统接口
  - SDK接口变更说明书
    - 前言
    - BLE SDK接口变更说明
  - SP31 SLP使用指南
    - 开源版本
  - USB HID复合设备开发指南
    - 前言
    - 概述
    - 实现方式
  - 代码框架说明
    - 前言
    - SDK模块框架
    - SDK目录结构
    - SDK目录说明
  - 低功耗FAQ
    - 前言
    - 系统无法睡眠
    - IO无法唤醒系统
    - 唤醒后外设异常
    - 低功耗导致OTA升级异常
    - 功耗比预期高
    - 锁中断导致BT业务阻塞
    - 概率性狗超时
    - 供电模式&软件配置
    - 提前唤醒时间问题
  - 低功耗sample使用指南
    - 前言
    - 编译&测试
    - 系统状态管理
    - 用户指南
  - 低功耗开发指南
    - 前言
    - 低功耗概述
    - 低功耗方案
    - 开发指引
    - 功耗优化
    - 常见问题
  - 功率配置说明书
    - 前言
    - 射频功率配置说明
  - 升级方案使用指南
    - 前言
    - 概述
    - 升级包制作
    - 升级包传输
    - 升级包保存
    - 升级包本地升级
    - FAQ
  - 快速入门指南
    - 前言
    - 文档目录
    - 环境搭建
    - 基础功能开发
    - 调优
    - 特性开发
    - 测试报告
  - 星闪应用层SLE-Link协议
    - 前言
    - 概述
    - SLE Frame格式定义
    - 服务接口定义
    - 交互流程示例
  - 星闪软件开发指导书
    - 前言
    - 概述
    - Device Discovery接口
    - Connection Manager接口
    - SSAP Server接口
    - SSAP client接口
    - Low Latency接口
    - Transmission Manager接口
    - SLE Passkey接口
    - SLE Channel Map 接口
  - 红外学习使用指南
    - 前言
    - 红外学习方式
    - 通过比较器进行红外学习
    - 使用指南
  - 蓝牙软件开发指导书
    - 前言
    - 概述
    - GAP接口
    - GATT server接口
    - GATT client接口
  - 设备驱动开发指南
    - 前言
    - Pinctrl
    - GPIO
    - UART
    - SPI
    - I2C
    - ADC
    - DMA
    - PWM
    - WDT
    - Timer
    - Systick
    - TCXO
    - Flash
    - SFC
    - QDEC
    - KEYSCAN
    - PDM
    - USB_HID
    - USB_DFU
    - I2S
    - TRNG
    - 附：MIDDLEWARE
  - 音频编解码开发指导书
    - 前言
    - 概述
    - Audio Encoder
    - Audio Decoder
    - 调试与功能
- 工具资料
  - BurnTool工具使用指导书
    - 前言
    - BurnTool工具简介
    - 操作指南
    - FAQ
  - HiSpark Studio使用指南
    - 前言
    - 工具简介
    - 开发环境搭建
    - 工程管理
    - 工程配置
    - 编译运行
    - 软件包烧录
    - 栈分析和镜像分析
    - 工程调试
    - 串口控制台工具
    - Kconfig配置
    - GUI工程创建与使用
    - 高阶分析功能使用
    - 常见错误

### 该页内容

- 前言
- 低功耗概述
  - 低功耗原理
  - 低功耗模式
- 低功耗方案
  - 睡眠条件
  - 睡眠唤醒流程
  - 唤醒源
  - 外设下电
- 开发指引
  - 主频&睡眠投票
  - 低功耗开发说明
  - 低功耗维测
  - 其他说明
    - BUCK/LDO供电模式配置
    - 32K时钟切换
    - GPIO相关
    - 32K时钟观测
    - XO快速起振配置
    - 外设保存恢复
    - 低速外设降频
    - WFI状态降频
    - 睡眠时关闭ulp_wdt
- 功耗优化
  - 睡眠电流
  - 工作电流
  - 保连电流
- 常见问题

# 前言

概述

本文档详细描述了BS2XV100的系统低功耗模式及应用开发指导，用于指导用户进行低功耗开发。

产品版本

与本文档对应的产品版本如下。

产品名称 | 产品版本
--- | ---
BS2X | V100

读者对象

本文档主要适用于以下工程师：

- 技术支持工程师

- 软件开发工程师

符号约定

在本文中可能出现下列标志，它们所代表的含义如下。

符号 | 说明
--- | ---
| 表示如不避免则将会导致死亡或严重伤害的具有高等级风险的危害。
| 表示如不避免则可能导致死亡或严重伤害的具有中等级风险的危害。
| 表示如不避免则可能导致轻微或中度伤害的具有低等级风险的危害。
| 用于传递设备或环境安全警示信息。如不避免则可能会导致设备损坏、数据丢失、设备性能降低或其它不可预知的结果。 “须知”不涉及人身伤害。
| 对正文中重点信息的补充说明。 “说明”不是安全警示信息，不涉及人身、设备及环境伤害信息。

修改记录

文档版本 | 发布日期 | 修改说明
--- | --- | ---
03 | 2024-08-29 | 更新“低功耗维测”小节内容。
02 | 2024-07-04 | 更新“低功耗维测”小节内容。
01 | 2024-05-15 | 第一次正式版本发布。 更新“主频&睡眠投票”小节内容。 更新“低功耗开发说明”小节内容。
00B04 | 2024-04-12 | 更新“低功耗模式”小节内容。 更新“主频&睡眠投票”小节内容。 更新“保连电流”小节内容。
00B03 | 2024-03-18 | 更新“低功耗原理”小节内容。 更新“低功耗模式”小节内容。
00B02 | 2024-02-29 | 更新“睡眠唤醒流程”小节内容。 更新“外设下电”小节内容。 更新“主频&睡眠投票”小节内容。 更新“低功耗维测”小节内容。
00B01 | 2024-01-26 | 第一次临时版本发布。

# 低功耗概述

## 低功耗原理

低功耗的本质是指从功耗的角度对电子设备的设计进行优化，以达到在满足功能需求的同时，尽可能降低功耗的目的。通常涉及到对硬件设计、软件优化、材料选择等方面的深入研究和优化。对软件设计而言，可以通过系统空闲时CPU停止工作，中断或事件唤醒后继续工作等方法来优化功耗。对于无OS运行的系统而言，程序可以“随时随地”进低功耗；但是对于带OS的系统，系统无法“随时随地”，必须遵循OS的运行流程。

在OS中，通常包含一个IDLE任务，该任务的优先级最低且一直保持就绪状态，当高优先级任务阻塞时，OS执行IDLE任务。一般地，未进行低功耗处理时，CPU在IDLE任务中循环执行空指令。低功耗管理组件在IDLE任务中，通过对CPU、时钟和设备等进行管理，从而有效降低系统的功耗，系统唤醒时再对CPU、时钟和设备等进行恢复，从而保证程序在退出低功耗后能正常运行。

图 1 OS低功耗

BS2XV100使用的操作系统为LiteOS，低功耗管理接口在LiteOS的IDLE线程中已经被调用，无需应用层主动调用，满足睡眠条件即可进入睡眠。

## 低功耗模式

表 1 低功耗模式说明

模式 | 芯片状态 | 特点
--- | --- | ---
WFI模式 | CPU停止工作。 部分时钟降频/关闭。 | WFI即Wait For Interrupt ，所有中断都能打断这一状态，让CPU继续工作。 OsTick正常保持（周期：1ms）。
浅睡模式 | CPU不下电，RAM不下电，所有外设可控下电。 只支持部分外设中断唤醒。 | 蓝牙/星闪广播/连接保持正常。 支持GPIO输出电平保持。
深睡模式 | CPU下电，RAM不下电，ULP_GPIO、ULP_WDT以外其他外设下电。 只支持少数外设中断唤醒。 | 蓝牙/星闪广播/连接保持正常。 uapi_gpio_set_val输出保持不生效，uapi_pin_set_pull管脚上下拉继续生效。 osal_timer定时功能不受影响。 用户自己初始化的外设，唤醒后需自行恢复。

# 低功耗方案

## 睡眠条件

图 1 睡眠条件

- 睡眠否决票

  添加睡眠否决票接口：errcode_t uapi_pm_add_sleep_veto(pm_veto_id_t veto_id)

  移除睡眠否决票接口：errcode_t uapi_pm_remove_sleep_veto(pm_veto_id_t veto_id)

  系统初始化时，有调用“uapi_pm_add_sleep_veto(PM_VETO_ID_MCU)”接口投了一票睡眠否决票，如想让系统进睡眠则需要移除该否决票，调用“uapi_pm_remove_sleep_veto(PM_VETO_ID_MCU)”即可。

- 空闲时间

  系统空闲时间由LiteOS管理，在睡眠投票满足时，睡眠管理接口中会判断睡眠时间是否满足深睡阈值，满足即进到深睡流程。低功耗管理接口会根据系统空闲时间添加唤醒计时器，保证系统能在预期时间点醒来。

> 说明：

> - 系统空闲时间受用户自己创建的线程/定时器影响，如果睡眠否决票已被全部移除，但是系统无法睡眠或者被频繁唤醒，请用户自行检查业务代码中是否有不合理的设计。

> - 如果系统当前处于广播态/连接态，系统也会周期性的醒来以维持广播/连接。

## 睡眠唤醒流程

图 1 睡眠唤醒流程

上述流程见“pm_sleep.c”中的“uapi_pm_enter_sleep”接口。

> 说明： Tickless：即OsTick减少，BS2X的OsTick是用外部Timer中断实现的（周期：1ms），系统睡眠前会主动关闭该Timer，系统唤醒后会根据实际睡眠时间对OsTick进行补偿，以保证OS线程/定时器调度不受睡眠影响。

## 唤醒源

- 浅睡唤醒源

- 深睡唤醒源

代码位置：middleware/chips/bs2x/pm/pm_sleep/pm_sleep_porting.c

> 说明：

> 1. 唤醒源使能本身并不会增加功耗，不要因为系统频繁唤醒就侵入式修改/删除唤醒源。有异常唤醒就正面定位，不建议采用删除唤醒源的方式规避！

> 2. 实际上，用户在投票睡眠后，即可当成所有外设都下电了，最终外设唤醒是通过ulp_gpio唤醒的。

> 3. 如果用户有定时唤醒的需求，有两种方式可以实现，第一种通过线程延时（osal_msleep）等待，第二种可通过软Timer（osal_timer_start）。

## 外设下电

表 1 外设下电

序号 | 驱动 | 深睡外设下电说明 | 恢复说明
--- | --- | --- | ---
1 | Pinctrl | mode下电、pull不下电、ds不下电。 | 直接使用uapi_pin_set_mode恢复各个外设的管脚模式即可。
2 | uapi_gpio | 下电，睡眠不支持唤醒，唤醒中断需注册于ulp_gpio中，唤醒后挂在本IP的中断可以正常响应。 睡眠时uapi_gpio本身会下电，SDK里已将uapi_gpio的输出配置同步到ulp_gpio，故睡眠时IO输出可保持。 | 参照正常流程恢复。
3 | UART | 下电，唤醒时SDK代码中已默认恢复。 | 通过 CONFIG_UART_SUPPORT_LPM 控制SDK恢复UART。
4 | I2C | 下电，需用户自行恢复。 | 参照正常流程。
5 | ADC | 下电，需用户自行恢复。 | 参照正常流程。
6 | DMA | 下电，需用户自行恢复。 | 参照正常流程。
7 | PWM | 下电，需用户自行恢复。 | 参照正常流程。
8 | WDT | 下电，SDK唤醒时已默认恢复。 | 通过CONFIG_WATCHDOG_SUPPORT_LPM 控制SDK恢复WDT。
9 | uapi_timer | 下电，可SDK恢复和补偿。 | 通过CONFIG_TIMER_SUPPORT_LPM控制 （不建议开，会增加保连场景的工作时间）。
10 | uapi_rtc | 下电，需用户自行恢复。 | 通过CONFIG_RTC_SUPPORT_LPM控制 （不建议开，会增加保连场景的工作时间）。
11 | Systick | 下电，需用户自行恢复。 | 通过CONFIG_SYSTICK_SUPPORT_LPM控制SDK恢复。
12 | Tcxo | 下电，唤醒时SDK代码中已默认恢复。 | 通过CONFIG_TCXO_SUPPORT_LPM控制SDK恢复。
13 | SFC | 下电，唤醒时SDK代码中已默认恢复。 | 通过CONFIG_SFC_SUPPORT_LPM控制SDK恢复
14 | 外部Flash | 非芯片供电，Flash所用SPI等需用户自行恢复。 | -
15 | SPI | 下电，需用户自行恢复。 | uapi_spi_suspend/uapi_spi_resume。
16 | Qdec | 下电，需用户自行恢复。 | 参照正常流程。
17 | Keyscan | 下电，需用户自行恢复。 | 参照正常流程。
18 | osal_timer | 下电，唤醒时SDK代码中已默认恢复。 | -
19 | ulp_gpio | 不下电，建议该GPIO只用来唤醒。 | -
20 | ulp_rtc | 只用来在睡眠流程定时唤醒和计算timer补偿用。 | -
21 | ulp_wdt | 不下电，睡眠场景保持该wdt在的话需注意喂狗。 | -
22 | RAM&内部Flash | 不下电。 | -

> 说明： BS2X系统深睡时，绝大多数外设均下电，基础外设，如sfc、wdt、tcxo、uart、osal_timer等在SDK中有恢复，其他由用户初始化的外设，在唤醒后需用户进行恢复，该流程放在用户的低功耗状态机中自行管理即可。

# 开发指引

时钟/电源管理逻辑已在SDK中配置，用户不必关心时钟树/电源树具体结构，对于用户所需要的低功耗相关接口会在下面介绍。

## 主频&睡眠投票

1. 主频配置

   对于CPU频率的配置提供2个档位即32M、64M，分别调用以下接口即可：

   （需#include "pm_clock.h"）

   - 主频32M：

     uapi_clock_control(CLOCK_CONTROL_FREQ_LEVEL_CONFIG, CLOCK_FREQ_LEVEL_LOW_POWER);

   - 主频64M：

     uapi_clock_control(CLOCK_CONTROL_FREQ_LEVEL_CONFIG, CLOCK_FREQ_LEVEL_HIGH);

   - 获取主频：

     uapi_clock_crg_get_freq(CLOCK_CRG_ID_MCU_CORE);

2. 睡眠投票

   （需#include "pm_veto.h"）

   - 添加睡眠否决票：errcode_t uapi_pm_add_sleep_veto(pm_veto_id_t veto_id)

   - 移除睡眠否决票：errcode_t uapi_pm_remove_sleep_veto(pm_veto_id_t veto_id)

   - 添加带超时的睡眠否决票：errcode_t uapi_pm_add_sleep_veto_with_timeout(pm_veto_id_t veto_id, uint32_t timeout_ms)，

     可以控制系统在指定时间内不进入睡眠，超时时间到了之后自动清除否决投票。

## 低功耗开发说明

BS2X睡眠投票使用的是否决票接口，即如果没有模块进行投票，则系统在空闲时间满足时会进入深睡眠。

SDK中当前投了一票否决票，即在“uapi_pm_lpc_init”中调用“uapi_pm_add_sleep_veto(PM_VETO_ID_MCU);”投否决票，如图1所示。

图 1 SDK默认否决投票

所以当前SDK只会在系统空闲时进入“WFI”，如果用户需要让系统进睡眠，还需要按照下面进行配置。

- 用户如果需要让MCU进睡眠时，可以调用“uapi_pm_remove_sleep_veto(PM_VETO_ID_MCU);”接口，否决票为0，系统即可进入睡眠。

- uapi_pm_add_sleep_veto和uapi_pm_remove_sleep_veto成对出现，调用uapi_pm_add_sleep_veto增加否决票（系统无法睡眠），调用uapi_pm_remove_sleep_veto移除否决票（系统可睡眠）。

- 另外又提供了带超时的投票接口“uapi_pm_add_sleep_veto_with_timeout”，调用该接口时需要传入一个超时时间参数（单位：ms），可以控制系统在指定时间内不进入睡眠，超时时间到了之后自动清除否决投票。

> 说明： 用户在低功耗管理时应该自己设计系统状态机，如：何时进保连、何时进睡眠、保连参数配置、唤醒时参数恢复等等，这些只能由上层业务实现，上层业务通过调用“添加/移除睡眠否决票”的接口进而控制系统状态切换。 BS2X SDK提供了一套简单状态机管理的代码，详细说明见《BS2XV100 低功耗sample使用指南》

## 低功耗维测

1. 中断&任务调度

   添加编译宏（config.py中添加）：OS_DFX_SUPPORT，程序运行时会有如下打印：

   - app_main初始化时打印task id和task name的对应关系；或者发送AT命令“AT+OSDFXPRINT”也可以进行打印。

   - 在周期性任务中按照调用顺序，从前往后打印“任务ID”和“中断号”。

   - 中断号见：chip_core_irq.h。

2. 工作&空闲时间统计

   product_evb_standard.h 文件中打开宏：PM_MCPU_MIPS_STATISTICS_ENABLE

3. 唤醒原因打印

   product_evb_standard.h 文件中打开宏：PM_SLEEP_DEBUG_ENABLE，深睡流程唤醒源见打印“ulp-wkup evt”，对应bit为1则表示是该唤醒源唤醒，各bit对应唤醒源为：

   bit1：ulp_gpio；

   bit2：ulp_rtc（包含task中的osal_msleep行为定时调度和osal_timer软调度）;

   bit3：osc_en（和BT业务有关，收发数据前需提前唤醒）；

   bit4：NFC；

   bit0：较为特殊，一般是由于在睡眠过程中被其他唤醒源唤醒导致，定位原因仍需看其他bit。

4. 获取投票信息：pm_veto_t *uapi_pm_veto_get_info(void)

5. 获取睡眠信息：sleep_info_t *uapi_pm_get_sleep_info(void)，需打开kconfig宏：CONFIG_PM_SLEEP_RECORD_ENABLE

6. task timer和sw timer打印：使能宏OS_TIMER_DEBUG_SUPPORT，发送AT命令“AT+OSTIMERPRINT”；或者调用接口os_task_timer_print和os_sw_timer_print进行打印；只看sw timer的话，也可以调用接口os_sw_timer_print_flag_set控制软timer调度时进行打印。

7. 睡眠投票和BT状态打印：使能宏SLP_VETO_AT_SUPPORT，发送AT“AT+PMVETOINFO”即可打印投票信息和BT状态信息。

> 说明： 维测会增加软件运行时间，前期调试和问题定位时可以打开，正式版本建议全部关闭。

## 其他说明

### BUCK/LDO供电模式配置

参考《BS2XV100 硬件指南》，芯片内部电源模块支持BUCK模式和LDO模式供电。

通常推荐芯片按照BUCK模式设计电路，效率高。如果对PCB面积有约束，且对模块的功耗不敏感，可采用LDO模式。

默认SDK版本为BUCK模式，使用LDO模式时需打开宏（CONFIG_POWER_SUPPLY_BY_LDO），配置如下：

### 32K时钟切换

BS2X芯片32K时钟可以选用内部RC也可以选用外部XO，SDK默认使用的是内部RC32K时钟，用户如需选用XO32K，可以通过配置宏“CONFIG_XO_32K_ENABLE”进行切换，如下所示：

### GPIO相关

GPIO中断注册

睡眠时uapi_gpio接口对应驱动会全部下电，所以无法通过工作时注册的uapi_gpio中断唤醒，需要用户通过ulp_gpio接口注册中断。uapi_gpio可注册32个中断，和Pin脚一一对应；ulp_gpio只能注册8个中断，需自定义进行Pin脚绑定。

- 唤醒中断配置接口：void ulp_gpio_int_wkup_config(ulp_gpio_int_wkup_cfg_t *cfg, uint8_t array_num)，睡眠前将所需的IO注册到唤醒中断上。一般情况下，uapi_gpio和ulp_gpio只能使用一个，所以睡眠前需去初始化uapi_gpio，并初始化ulp_gpio，之后再注册ulp_gpio中断。以鼠标按键为例，使用示例如下：

      static ulp_gpio_int_wkup_cfg_t g_wk_cfg[] = {
          { 1, CONFIG_MOUSE_PIN_QDEC_A, true, ULP_GPIO_INTERRUPT_FALLING_EDGE, ulp_gpio_wkup_handler },    // qdec唤醒
          { 2, CONFIG_MOUSE_PIN_LEFT, true, ULP_GPIO_INTERRUPT_FALLING_EDGE, ulp_gpio_wkup_handler },      // 左键唤醒
          { 3, CONFIG_MOUSE_PIN_RIGHT, true, ULP_GPIO_INTERRUPT_FALLING_EDGE, ulp_gpio_wkup_handler },     // 右键唤醒
          { 4, CONFIG_MOUSE_PIN_MID, true, ULP_GPIO_INTERRUPT_FALLING_EDGE, ulp_gpio_wkup_handler },       // 中键唤醒
          { 5, CONFIG_MOUSE_PIN_MONTION, true, ULP_GPIO_INTERRUPT_FALLING_EDGE, ulp_gpio_wkup_handler },   // Sensor唤醒
      };
      // 睡眠前切换到ulp_gpio并注册中断
      static void mouse_enable_ulpgpio_wkup(void)
      {
          uapi_gpio_deinit();
          ulp_gpio_init();
          ulp_gpio_int_wkup_config(g_wk_cfg, sizeof(g_wk_cfg) / sizeof(ulp_gpio_int_wkup_cfg_t));
      }
      // 唤醒后切换到uapi_gpio
      static void mouse_disable_ulpgpio_wkup(void)
      {
          ulp_gpio_deinit();
          uapi_gpio_init();
      }

- 多个IO口绑定到一个mask接口：void ulp_gpio_mask_pin_set(ulp_gpio_wk_t wk_sel, uint32_t pin_map)，ulp_gpio只能注册8个中断，如果多于8个IO口要响应唤醒中断，需要使用该接口将多个IO口绑定到一个mask上，参数pin_map每个bit对应一个IO（bit0即s_mgpio0），对应bit为1即表示选定对应IO。

- 参数说明：

      typedef struct ulp_gpio_int_wkup_cfg {
      /* ulp_gpio共有8个(0~7) */
      uint8_t ulp_gpio;
      /**
      *0~31：IO管脚，参考 pin_t 。
      *32：swd_clk管脚
      *33：swd_io管脚
      *34：gpio或mask0，低电平：0，高电平：1，可以将多个低电平管脚绑定成或mask0，中断触发选上升沿或高电平，一个脚被拉高即触发中断。
      *35：gpio与mask0，低电平：0，高电平：1，可以将多个高电平管脚绑定成与mask0，中断触发选下降沿或低电平，一个脚被拉低即触发中断。
      *36：gpio或mask1，低电平：0，高电平：1，可以将多个低电平管脚绑定成或mask1，中断触发选上升沿或高电平，一个脚被拉高即触发中断。
      *37：gpio与mask1，低电平：0，高电平：1，可以将多个高电平管脚绑定成与mask1，中断触发选下降沿或低电平，一个脚被拉低即触发中断。
      补充：mask管脚绑定可以使用接口 ulp_gpio_mask_pin_set。
      */
      uint8_t wk_mux;
      bool int_enable;
      ulp_gpio_interrupt_t trigger;
      ulp_gpio_irq_cb_t irq_cb;
      } ulp_gpio_int_wkup_cfg_t;

GPIO输出保持

系统深睡时，uapi_gpio会下电，所以在睡眠时需要通过ulp_gpio进行GPIO输出。当前SDK中已自动在睡眠时将uapi_gpio输出配置同步到ulp_gpio，唤醒后再同步回来。如果有GPIO输出需求，直接使用uapi_gpio接口配置即可；如果用户不需要使GPIO保持输出功能，同样，使用uapi_gpio_set_dir接口将其配置成输入功能即可。

IO管脚IE配置

IE即Input Enable，即需要保持IO为输入功能（接收中断）时需要使用uapi_pin_set_ie接口，将对应IO口配置使能。

为了避免IO上不必要的漏电，当前SDK中已经将默认管脚的IE功能disable，用户如果需要对应IO口能响应GPIO中断，需要将IE使能。另外，如UART RX等管脚IE也需要使能，当前SDK中也已经按需配置。

IO状态打印&配置接口

- 状态打印接口：void pm_gpio_state_print(void)，可以在睡眠前调用该接口打印出所有管脚的管脚ID、管脚模式、输入输出方向、内部上下拉状态、输出状态。

- IO状态配置接口：void pm_gpio_group_config(gpio_info_cfg_t *cfg, uint8_t array_num)，该接口实现旨在提供给用户一个IO整体配置的方法（也可自行实现），搭配状态打印接口使用，可以在睡眠前进行IO配置和显示，进而辅助功耗优化。

> 说明： 系统深睡功耗排查，主要是排查IO漏电，而IO上下拉/输入输出配置一般又和外围电路有关。IO状态打印&配置接口，可以对IO进行整体配置及打印，进而和硬件同事相互对齐即可。

### 32K时钟观测

SDK中提供了观测32K时钟的接口：uapi_clock_control(CLOCK_CONTROL_32K_TEST_ENABLE, xxx)，即使用Pin xxx口观测32K时钟，该接口使用时需打开宏“CLOCK_TEST_ENABLE”。

### XO快速起振配置

当前SDK中XO起振时间按照1ms配置，如果XO晶体电容为8pF的话，XO起振时间可以缩短到250us。可以通过使能宏CONFIG_PM_XO_FAST_START_ENABLE缩短XO起振时间，进而减少“工作时间”并降低功耗。宏配置如下：

### 外设保存恢复

根据2.4章节知道：睡眠时绝大部分外设是自动掉电的，唤醒时需要软件流程重新配置恢复，当前SDK中默认已进行部分外设恢复。

个别外设用户也可以配置不恢复，以缩减唤醒后的软件工作时间，进而降低一些保连功耗。这些外设包括：watchdog、uart、cpu_trace，可分别关闭宏 CONFIG_WATCHDOG_SUPPORT_LPM、CONFIG_UART_SUPPORT_LPM、CONFIG_CPU_TRACE_SUPPORT_LPM。

- uapi_watchdog休眠时下电，唤醒后默认上电（超时时间为8s），唤醒后不主动恢复也不会影响其功能；休眠时ulp_wdt可以保持不下电，可以在睡眠期间起到保护作用。

- uart当前睡眠唤醒前后做了保存和恢复，该动作用户可以放到自己的代码中去做，可以直接调用deinit和init接口重新初始化即可。

- cpu_trace功能会在每次函数跳转进行记录，在异常后可以导出trace分析函数接口调用轨迹。在正式商用版本上，该功能也可以考虑关掉。

### 低速外设降频

当前SDK固定将低速外设（包括timer、uart l0、uart l1、i2c、keyscan、qdec）时钟源的频率固定配置为32M，为进一步降低工作功耗，用户可以打开宏 CONFIG_REDUCE_PERP_LS_FREQ 降低低速外设时钟源频率（8M），如下所示：

该宏打开时，部分外设总线频率会降低，上述外设性能会稍微有一些影响，用户根据测试情况可以考虑带上该优化配置。

### WFI状态降频

> 须知： “低速外设降频”和“WFI状态降频”，在USB工作场景下慎用（性能不足），其他场景暂未发现问题。

CPU空闲时系统进入WFI状态，为进一步降低该状态下的功耗，可以打开宏 CONFIG_REDUCE_FREQ_DURING_WFI，降低该状态时的CPU和总线频率，以及临时关闭flash时钟，配置如下：

### 睡眠时关闭ulp_wdt

> 须知：

> 1. 通过上述方法关闭ulp_wdt时，软件会同时降低32k时钟（内置RC32K）的驱动能力，32k时钟精度会受到影响，所以建议在只有GPIO唤醒的情况下使用，即断连、无周期性定时器和任务。

> 2. 睡眠时如果关闭ulp_wdt，休眠唤醒期间部分软硬件流程无法守护住，如果在此期间芯片异常，系统则无法主动复位，不建议没有主动复位按键或插拔电池复位的产品使用。

系统睡眠时uapi_watchdog下电，ulp_wdt不下电。深睡场景，为了防止狗超时，系统需要唤醒去喂狗，对于长时间不工作场景，每次让系统醒来专门去喂狗，既增加功耗也显得不太必要，所以用户可以打开宏 CONFIG_SUPPORT_CLOSE_ULP_WDT_DURING_SLP 控制系统在休眠时关闭ulp_wdt，如下：

打开上述宏之后可以使用接口 void pm_close_ulp_wdt_during_slp(bool close) 控制休眠时是否关闭ulp_wdt。

# 功耗优化

芯片功耗分为静态功耗和动态功耗。优化深睡功耗时，由于时钟都已关闭，所以基本没有动态功耗，主要优化静态功耗；对于工作场景，则主要优化动态功耗。下面将具体介绍睡眠电流和工作电流的优化方法。

## 睡眠电流

系统睡眠时，高频时钟都已关闭，CPU和外设也均下电，此场景如果电流异常，主要是IO漏电导致。

- 硬件上可通过测量每个IO管脚电压，进而判断漏电情况，然后软件将IO电压配平即可。

- GPIO非必须尽量不要配置成输出模式，建议配置成输入模式。

- 如果IO管脚上没有对接外围器件的话，建议该IO管脚配置成输入下拉。

- 对于部分管脚，如I2C、QSPI_CS等一般配置成输入上拉功耗最低，用户可自行排查测试。

- IO管脚如果配置成高阻态的话，IO管脚上可能会有积攒电荷，一般情况下，配置成上拉/下拉状态更优。

> 说明： Qdec使用的A/B两个管脚，为了减少漏电，一般该管脚都会板级上加上拉电阻，由于该管脚状态不定，软件配置上拉或者下拉都会漏电，所以该管脚一般都会配置成浮空态。

## 工作电流

- SDK中已经自适应的进行了电源和时钟的开关，所以对于工作功耗优化，主要在于主频配置和IO配置。

- CPU工作占空比会影响功耗，例如日志打印较多会造成CPU进WFI的时间缩短，进而增加功耗；此外代码在RAM中的执行速度比Flash上高很多，所以用户为了进一步降低工作电流，需提取热点函数到RAM上。

- 另外，用户调用BTH接口配置的interval、latency和发射功率等参数也会影响工作功耗。

## 保连电流

一般地，睡眠电流和工作电流优化完毕之后，保连电流不需要额外的优化了。保连电流会受连接参数 interval和latency 影响比较大。

# 常见问题

请参见《BS2XV100 低功耗FAQ》。