杰理 SDK 文档中心
首页
首页
  • SDK 概述与入门

    • SDK 总览
    • 支持芯片与蓝牙认证
    • 工程结构导航
  • 开发环境与构建

    • 环境搭建与工具链安装
    • 编译指南与工程选择
    • 烧录与生产工具
  • BLE 透传/数传应用

    • 透传应用框架与处理模块
    • 透传与数传示例
    • 多连接与自定义服务示例
    • FindMy 与查找网络示例
  • HID 人机交互应用

    • 键盘与按键设备示例
    • 鼠标设备示例
    • 遥控器示例
    • HID 蓝牙应用模块
  • 公共 BSP 模块

    • 按键、编码器与红外输入
    • 传感器驱动
    • LED 与显示控制
    • 串口与 USB 通信
    • 存储、参数与时钟
    • 电源与温度管理
    • 消息、内存与系统配置
    • OTA 升级框架
  • 蓝牙协议栈与库

    • BLE 控制器与协议栈适配
    • 经典蓝牙 BR/EDR 支持
    • 第三方蓝牙协议
    • 设备管理框架
    • DUT 测试与射频认证
  • 构建系统与开发工具

    • Makefile 构建系统
    • 固件后处理与配置工具
    • 辅助脚本与库合并
  • 文档与硬件资料

    • AT 命令参考
    • 硬件参考资料
    • SDK 文档与在线资源

电源与温度管理

本文档介绍 fw-AW33N_BLE_SDK 的电源与温度管理机制,涵盖应用层电源管理模块(app_power_mg)、低功耗调度框架(power_manage)、芯片级电源流程(power_app)以及低电量检测、软关机等关键流程。

Purpose and Scope

本页面覆盖 AW33N BLE SDK 中与电源相关的能力:

  • 应用层电源管理:低电量检测、VBAT 采样、低电事件上报、软关机(app_power_mg.c/h);
  • 低功耗调度框架:lp_target / lp_request / deepsleep_target 注册机制、低功耗等级(浅睡/睡/深睡/软关)、PMU 硬件操作钩子(power_manage.h);
  • 芯片级电源流程:睡眠进出回调、软关机回调、早期/后期电源初始化(power_app.c)。

未纳入本页的内容:蓝牙协议栈内部的连接/广播功耗管理、充电管理(POWER_EVENT_POWER_CHARGE 仅作事件透传)、以及具体产品的按键唤醒/IO 唤醒配置属于各应用工程范畴。温度管理:在本次已读取的电源源码中未发现独立的应用层温度管理实现;温度相关控制(如 PMU 热保护)通常由芯片硬件/配置工具(如 post_build/bd57/AW33N_config_tool/conf/source/board/lowpower_v1.lua)承载,本页在"温度管理"一节中如实说明。

Overview

电源管理在 BLE 低功耗设备中承担三个核心职责:

  1. 电量感知:通过 GPADC 周期性采样 VBAT,计算百分比电量,供 UI(如低电 LED、提示音)与事件上报使用;
  2. 低电保护:当电压低于 LVD 警戒线并持续一段时间后,触发软关机(soft poweroff),避免电池过放损坏;
  3. 功耗控制:系统空闲时由低功耗框架统一仲裁各模块(蓝牙、系统组)的休眠请求,选择浅睡/深睡/软关等级,并在唤醒后恢复。

整个系统采用"注册-查询-仲裁"的经典低功耗设计:每个需要参与低功耗决策的模块通过链接段(.lp_target、.lp_request、.deepsleep_target)静态注册回调,电源管理器遍历注册表查询是否空闲、仲裁最终休眠时长与等级。这种设计避免了模块间互相依赖,新增模块只需注册即可被统一调度。

Architecture

下图展示了电源管理系统的整体架构与数据流:

flowchart TD
    subgraph sg_App["应用层 (common/power_manage)"]
        APM["app_power_mg.c<br/>低电检测/事件/软关机"]
        LED["led_control<br/>低电LED闪烁"]
        BLE["ble_module_enable<br/>蓝牙模块开关"]
    end

    subgraph sg_Framework["低功耗框架 (power_manage.h)"]
        PMGR["_pmgr_hdl 电源管理器"]
        GROUP0["group0 (bluetooth)"]
        GROUP1["group1 (System)"]
        TARGET["lp_target 注册表"]
        REQUEST["lp_request 注册表"]
        DEEP["deepsleep_target 注册表"]
    end

    subgraph sg_Chip["芯片级 (bd57/power)"]
        PAPP["power_app.c<br/>睡眠/软关回调"]
        PHW["phw_dev_ops<br/>PMU硬件操作"]
        P33["P33 电源管理单元"]
        GPADC["GPADC<br/>VBAT采样"]
    end

    GPADC -->|"gpadc_battery_get_voltage"| APM
    APM -->|"POWER_EVENT_POWER_LOW"| LED
    APM -->|"power_set_soft_poweroff"| PAPP
    APM -->|"ble_module_enable"| BLE
    PMGR --> TARGET
    PMGR --> REQUEST
    PMGR --> DEEP
    PMGR --> GROUP0
    PMGR --> GROUP1
    PMGR -->|"low_power_suspend/resume"| PHW
    PHW --> P33
    PAPP -->|"sleep_enter/exit_callback"| PMGR

各组件职责:

  • app_power_mg.c:应用入口,初始化 VBAT 采样通道、启动低电扫描定时器、将低电事件转发给应用层(LED/关机)。
  • power_manage.h 框架:维护 _pmgr_hdl(含蓝牙组 group0 与系统组 group1),遍历注册表决定是否可休眠、休眠多久、进入哪一级休眠。
  • power_app.c:芯片 BSP 层,提供睡眠进出回调(矩阵按键 IO 处理、USB IO 高阻)、软关机钩子与电源早期/后期初始化。
  • phw_dev_ops:PMU 硬件操作抽象,覆盖 sleep/soff/deepsleep 各阶段的 prepare/enter/exit/post,是低功耗框架与 P33 硬件之间的唯一通道。

设计意图:分层隔离。应用层只关心"电量低不低、要不要关机",框架层只关心"哪些模块空闲、睡多久",BSP 层只关心"IO 怎么配、硬件怎么进睡"。任何一层变更都不影响其他层。

应用层电源管理(app_power_mg)

apps/app/bsp/common/power_manage/app_power_mg.c 是电源管理在应用层的中枢,围绕四个静态变量工作:

static uint8_t app_power_low_check = 0;
//低电检测电压,比lvd电压大300mV
static uint16_t app_power_lvd_warning;
static uint16_t app_power_vbat_voltage;
static uint16_t app_power_vbat_check_timer = 0;

Source: app_power_mg.c

app_power_lvd_warning 是低电警戒线,初始化为 POWEROFF_TONE_V + 300(即比关机提示音电压高 300mV),可由 app_power_set_lvd() 动态调整。LVD 警戒线与供电模式相关:

#if (TCFG_POWER_SUPPLY_MODE == 1) //VPWR
#define     POWEROFF_TONE_V             2700
#define     BATTERY_FULL_VALUE          3700
#else //IOVDD
#define     POWEROFF_TONE_V             2100
#define     BATTERY_FULL_VALUE          3000
#endif

Source: app_power_mg.c

设计意图:VPWR 与 IOVDD 两种供电方式下电池满电/关断电压不同,因此电量百分比计算与低电判定必须按供电模式区分,否则会出现"电量永远 0%"或"永不觉醒"的误判。

低电扫描与软关机流程

app_power_scan() 是低电检测的核心(由 sys_timer 每 2 秒触发一次):

static void app_power_scan(void *priv)
{
#if TCFG_SYS_LVD_EN && TCFG_ADC_VBAT_CH_EN
    static uint16_t low_power_cnt = 0;

    uint16_t vol = gpadc_battery_get_voltage();

    if (0 == vol) {
        return;
    }

    /* log_info("vbat voltage : %d\n", vol); */
    if (vol <= LOW_POWER_VOL)  {
        log_info("vbat voltage : %d\n", vol);
        log_error(LOW_POWER_LOG);
        low_power_cnt++;
        // 10s后打开低电led闪烁行为
#if TCFG_LED_ENABLE
        if (low_power_cnt == 5) {
            led_low_power(1);
            app_power_low_check = 1;
        }
#endif
        // 检测低电多次后进入软关机
        if (low_power_cnt == (LOW_POWER_SOFTOFF_TIME / LOW_POWER_CHECK_INTERVAL) + 1) {
            app_power_event_to_user(POWER_EVENT_POWER_LOW);
        }
    } else {
        low_power_cnt = 0;
#if TCFG_LED_ENABLE
        if (app_power_low_check) {
            led_low_power(0);
            app_power_low_check = 0;
        }
#endif
    }

    app_power_vbat_voltage = vol;
#endif
}

Source: app_power_mg.c

关键细节:

  • vol == 0 时直接返回,防止采样异常(如 ADC 未就绪)导致误判;
  • 采用连续计数而非单次判断:必须连续 LOW_POWER_SOFTOFF_TIME / LOW_POWER_CHECK_INTERVAL + 1 = 60s/2s + 1 = 31 次低于警戒线才上报 POWER_EVENT_POWER_LOW,这是防抖设计,避免电压瞬时跌落(如蓝牙发射瞬间)触发关机;
  • 电压恢复后计数清零,LED 低电闪烁关闭,实现滞后回差;
  • 第 5 次(约 10 秒)时先打开低电 LED 提示,再在约 60 秒时软关机——给用户"还能再撑一会儿"的缓冲。

事件上报通过 app_power_event_to_user() 封装为系统事件:

void app_power_event_to_user(uint8_t event)
{
    struct sys_event *e = event_pool_alloc();
    if (e == NULL) {
        log_info("Memory allocation failed for sys_event");
        return;
    }
    e->type = SYS_DEVICE_EVENT;
    e->arg  = (void *)DEVICE_EVENT_FROM_POWER;
    e->u.dev.event = event;
    e->u.dev.value = 0;
    main_application_operation_event(NULL, e);
}

Source: app_power_mg.c

事件统一以 DEVICE_EVENT_FROM_POWER 源注入应用主循环,由 app_power_event_handler() 消费。内存不足时直接放弃上报并打日志——低电场景下内存可能紧张,宁可丢弃事件也不能让系统崩溃。

事件处理侧(app_power_event_handler)在收到 POWER_EVENT_POWER_LOW 时删除 VBAT 检测定时器并调用软关机回调:

case POWER_EVENT_POWER_LOW:
    if (app_power_vbat_check_timer) {
        sys_timer_del(app_power_vbat_check_timer);
        app_power_vbat_check_timer = 0;
    }

    if (set_soft_poweroff_call) {
        log_info("POWER_LOW TO SOFT_POWEROFF");
        set_soft_poweroff_call();
    }
    break;

Source: app_power_mg.c

先停定时器再关机,保证关机流程不会被打断;set_soft_poweroff_call 由注册方注入,解耦事件与具体关机实现。

软关机实现

app_power_set_soft_poweroff() 按低功耗模式分派:

void app_power_set_soft_poweroff(void *priv)
{
#if (TCFG_LOWPOWER_PATTERN == SOFT_MODE)
    log_info(">>>>>>>Enter softoff");
    power_set_soft_poweroff();
#elif (TCFG_LOWPOWER_PATTERN == SOFT_BY_POWER_MODE)
    log_info(">>>>>>>Enter softoff by poweroff");
    key_active_num_set(0);
    app_power_soft.power_soft_handle = sys_timeout_add(NULL, soft_by_power_mode, LOW_POWER_SOFTOFF_BT_EXIT_TIME);//等待蓝牙基带close
#endif
}

Source: app_power_mg.c

SOFT_MODE:立即调用 power_set_soft_poweroff() 直接软关机。

SOFT_BY_POWER_MODE:先清按键计数,再延迟 LOW_POWER_SOFTOFF_BT_EXIT_TIME(100ms)执行 soft_by_power_mode()。这 100ms 是给蓝牙基带关闭 ADV/SCAN 的窗口,随后以 LOW_POWER_KEEP(-2) 进入"一直保持不退出"的深度休眠。唤醒时 power_wakeup_init() 恢复:

void power_wakeup_init(void)
{
    if (app_power_soft.power_soft_flag) {
        putchar('}');
        app_power_soft.power_soft_flag &= ~BIT(0);
        //open bt
        wdt_init(WDT_8S);
        /* sys_timer_init(); */
        ble_module_enable(1);
        app_to_recover();
    }
}

Source: app_power_mg.c

唤醒序列为:清标志 → 重开看门狗(8s)→ 使能蓝牙模块 → 调用弱函数 app_to_recover()(应用可覆盖实现恢复逻辑)。putchar('{')/('}') 是调试用串口标记,标识休眠进出边界。

低功耗调度框架(power_manage)

apps/include_lib/cpu/bd57/asm/power/power_manage.h 定义了 SDK 统一的低功耗框架,核心是链接段注册表 + 分组仲裁。

模块空闲注册(lp_target)

每个参与低功耗决策的模块通过 REGISTER_LP_TARGET 注册到 .lp_target 链接段:

struct lp_target {
    char *name;
    level_handler_t level;
    idle_handler_t is_idle;
};

#define REGISTER_LP_TARGET(target) \
        const struct lp_target target SEC_USED(.lp_target)

Source: power_manage.h

低功耗等级枚举(从浅到深):

enum LOW_POWER_LEVEL {
    LOW_POWER_MODE_LIGHT_SLEEP = 1,
    LOW_POWER_MODE_SLEEP,
    LOW_POWER_MODE_DEEP_SLEEP,
    LOW_POWER_MODE_SOFF,

    LOW_POWER_MODE_EXIT = 0x10,
};

Source: power_manage.h

设计意图:level 回调返回该模块允许进入的最低等级,is_idle 回调判断模块是否空闲。框架取所有模块允许等级的最小值(即最保守的等级)作为系统休眠等级,保证任何模块都不会在未就绪时被强行休眠。

休眠操作契约(low_power_operation)

struct low_power_operation {
    const char *name;
    u32(*get_timeout)(void *priv);
    void (*suspend_probe)(void *priv);
    void (*suspend_post)(void *priv, u32 usec);
    void (*resume)(void *priv, u32 usec);
    void (*resume_post)(void *priv, u32 usec);
};

Source: power_manage.h

模块通过 low_power_get() / low_power_sys_get() 注册(蓝牙组/系统组),通过 low_power_put() 注销。生命周期为 get_timeout → suspend_probe → suspend_post → resume → resume_post,与 Linux PM 的 suspend/resume 回调链同构。low_power_sys_suspend() 等系统组 API 供非蓝牙系统模块使用,两组查询函数 lower_power_bt_group_query() / lower_power_sys_group_query() 分别汇总两组的最短超时。

主动请求注册(lp_request)

与"被动查询"互补,lp_request 允许线程主动请求进入/退出低功耗:

struct lp_request {
    char *name;
    u8(*request_enter)(u32 timeout);
    u8(*request_exit)(u32 timeout);
};

#define REGISTER_LP_REQUEST(target) \
        const struct lp_request target SEC_USED(.lp_request)

Source: power_manage.h

深睡目标注册(deepsleep_target)

深睡(RTC 唤醒类)模块注册 enter/exit/post 三回调,deepsleep_target_enter()/exit()/post() 由框架按序批量调用:

struct deepsleep_target {
    char *name;
    u8(*enter)(void);
    u8(*exit)(void);
    u8(*post)(void);
};

#define DEEPSLEEP_TARGET_REGISTER(target) \
        const struct deepsleep_target target SEC_USED(.deepsleep_target)

Source: power_manage.h

PMU 硬件操作抽象(phw_dev_ops)

框架与硬件之间的桥梁是 phw_dev_ops,覆盖从 sleep 到 deepsleep/soff 的全部阶段钩子:

struct phw_dev_ops {
    void *(*early_init)(u32 arg);
    u32(*init)(struct _phw_dev *dev, u32 arg);
    u32(*ioctl)(struct _phw_dev *dev, u32 cmd, u32 arg);

    u32(*sleep_already)(struct _phw_dev *dev, u32 arg);
    u32(*sleep_prepare)(struct _phw_dev *dev, u32 arg);
    u32(*sleep_enter)(struct _phw_dev *dev, u32 arg);
    u32(*sleep_exit)(struct _phw_dev *dev, u32 arg);
    u32(*sleep_post)(struct _phw_dev *dev, u32 arg);

    u32(*soff_prepare)(struct _phw_dev *dev, u32 arg);
    u32(*soff_enter)(struct _phw_dev *dev, u32 arg);
    u32(*soff_exit)(struct _phw_dev *dev, u32 arg);

    u32(*deepsleep_enter)(struct _phw_dev *dev, u32 arg);
    u32(*deepsleep_exit)(struct _phw_dev *dev, u32 arg);
};

Source: power_manage.h

框架句柄 _pmgr_hdl 内含两个休眠组、当前等级、固定大小的电源对象池与依赖 API 指针:

struct _pmgr_hdl {
    struct low_power_group group0;  //bluetooth
    struct low_power_group group1;  //System
    enum LOW_POWER_LEVEL level;

    struct _power_mem power_mem;

    struct pmgr_depend_api *api;
};

Source: power_manage.h

_power_mem 使用固定数组(POWER_LIST_SIZE = 5)而非动态分配,因为低功耗路径上不允许堆分配失败。

芯片级电源流程(power_app)

apps/app/bsp/cpu/bd57/power/power_app.c 提供 BSP 层电源实现,所有低功耗路径代码通过 LP_RUNCODE_AT(.lp_running.bsp.text) 段属性常驻 RAM——深睡时 Flash 可能不可访问,代码必须驻留 RAM 才能执行唤醒逻辑。

睡眠进入回调(关中断环境,禁止耗时操作与打印):

LP_RUNCODE_AT(.lp_running.bsp.text)
void sleep_enter_callback(u8 step)
{
#if KEY_MATRIX_EN
    extern void set_matrixkey_row_port_output();
    // 矩阵按键进低功耗前先把行IO拉低使其可以被唤醒
    set_matrixkey_row_port_output();
#endif
    /* 此函数禁止添加打印 */
    putchar('<');
    if (sleep_enter_callback_api) {
        sleep_enter_callback_api();
    }

    //USB IO打印引脚特殊处理
#if (CONFIG_UART_DEBUG_ENABLE && ((CONFIG_UART_DEBUG_PORT == IO_PORT_DP) || (CONFIG_UART_DEBUG_PORT == IO_PORT_DM)))
    usb_io_con = JL_PORTUSB->DIR;
#endif

    //配高阻需根据外围电路设计来决定
    usb_high_res();
}

Source: power_app.c

要点:

  • 矩阵按键行 IO 先拉低,保证休眠期间按键仍能产生唤醒边沿;
  • 若调试串口复用在 USB DP/DM 引脚,需保存其方向寄存器并在退出时恢复;
  • 进入前将 USB IO 配为高阻,降低休眠漏电;
  • sleep_set_enter_call_api() / sleep_set_exit_call_api() 允许应用注入额外回调。

软关机钩子 power_set_soft_poweroff_hook() 在关机前做 overlay 重载检查(sleep_overlay_check_reload),确保 Flash overlay 机制在唤醒后能正确重映射。电源早期/后期初始化分别由 power_early_flowing()(关 MCLR、配长按复位、保护调试/按键 IO、power_early_init)与 power_later_flowing()(pmu_trim、power_later_init、strc_trim_flow)完成。

核心流程

低电检测 → 软关机时序

sequenceDiagram
    participant Timer as sys_timer (2s)
    participant Scan as app_power_scan
    participant ADC as GPADC (VBAT)
    participant App as 应用事件循环
    participant LED as led_control
    participant SOFF as 软关机回调

    Timer->>Scan: 周期触发 app_power_scan()
    Scan->>ADC: gpadc_battery_get_voltage()
    ADC-->>Scan: 电压值 vol
    alt vol == 0 (采样异常)
        Scan-->>Scan: return (跳过本次)
    else vol <= LOW_POWER_VOL
        Scan-->>Scan: low_power_cnt++
        alt cnt == 5 (约10s)
            Scan->>LED: led_low_power(1)
        else cnt == 31 (约60s)
            Scan->>App: POWER_EVENT_POWER_LOW
            App->>App: 删除VBAT检测定时器
            App->>SOFF: set_soft_poweroff_call()
            SOFF-->>SOFF: 按低功耗模式进入软关机
        end
    else vol > LOW_POWER_VOL
        Scan-->>Scan: low_power_cnt = 0
        Scan->>LED: led_low_power(0)
    end

系统空闲 → 低功耗仲裁流程

flowchart TD
    Idle["系统空闲"] --> Query{"low_power_sys_is_idle()?"}
    Query -->|"否"| Stay["保持运行"]
    Query -->|"是"| Level["遍历 lp_target 计算<br/>允许的最低等级"]
    Level --> Group["蓝牙组/系统组分别<br/>查询超时 low_power_group_query"]
    Group --> Decide{"存在有效超时?"}
    Decide -->|"LOW_POWER_KEEP(-2)"| Deep["进入并保持休眠<br/>sys_power_down"]
    Decide -->|"正常超时"| Suspend["low_power_suspend<br/>suspend_probe/post"]
    Suspend --> Wake["唤醒 low_power_resume"]
    Wake --> Recover["resume_post 恢复外设"]
    Deep --> WakeUp["外部事件唤醒<br/>power_wakeup_init"]
    WakeUp --> Recover
    Recover --> Idle
    Stay --> Idle

关键点:LOW_POWER_KEEP(-2) 表示"进入低功耗并一直保持不退出"(由外部事件如按键/充电唤醒),LOW_POWER_NO_USE(-1) 表示传参无效、睡眠时长交由蓝牙协议栈决定,LOW_POWER_SET_MAX_TIME(4000000µs) 是显式设置的睡眠时长上限。

使用示例

初始化与电量获取

以下代码展示了电源管理模块的典型用法——初始化、启动低电检测、读取电压与百分比:

void app_power_init(void)
{
#if TCFG_ADC_VBAT_CH_EN
    app_power_lvd_warning_init();
    adc_add_sample_ch(AD_CH_PMU_VBAT);
    app_power_scan(NULL);
#endif
}

uint16_t app_power_get_vbat(void)
{
    return app_power_vbat_voltage;
}

uint8_t app_power_get_vbat_percent(void)
{
    uint16_t tmp_bat_val;
    uint16_t bat_val = app_power_get_vbat_level();

    if (bat_val <= POWEROFF_TONE_V) {
        return 0;
    }

    tmp_bat_val = app_power_remap_vbat_percent(bat_val);
    if (!tmp_bat_val) {
        tmp_bat_val = (uint32_t)(bat_val - POWEROFF_TONE_V) * 100  / (BATTERY_FULL_VALUE - POWEROFF_TONE_V);
        log_info("bat_val:%d, POWEROFF_TONE_V: %d, BATTERY_FULL_VALUE: %d\n", bat_val, POWEROFF_TONE_V, BATTERY_FULL_VALUE);
        if (tmp_bat_val > 100) {
            tmp_bat_val = 100;
        }
    }
    return (uint8_t)tmp_bat_val;
}

Source: app_power_mg.c

说明:app_power_init() 先初始化 LVD 警戒线并加入 VBAT 采样通道,再立即做一次采样作为初始值。app_power_get_vbat_percent() 在满电值以下做线性映射,app_power_remap_vbat_percent() 是弱函数(默认返回 0),产品可覆盖它实现非线性电池曲线(锂电池放电曲线非线性,线性映射仅作默认)。

启动周期低电检测:

void app_power_vbat_check()
{
    app_power_vbat_check_timer = sys_timer_add(NULL, app_power_scan, LOW_POWER_CHECK_INTERVAL);
}

Source: app_power_mg.c

动态调整 LVD 警戒线

void app_power_set_lvd(uint16_t lvd_value)
{
    app_power_lvd_warning = lvd_value;
}

Source: app_power_mg.c

模块注册低功耗目标(框架用法)

框架的使用方式是在任意 .c 文件中定义 struct lp_target 并静态注册,链接器自动将其放入 .lp_target 段:

struct lp_target {
    char *name;
    level_handler_t level;
    idle_handler_t is_idle;
};

#define REGISTER_LP_TARGET(target) \
        const struct lp_target target SEC_USED(.lp_target)

Source: power_manage.h

框架遍历注册表:

#define list_for_each_lp_target(p) \
    for (p = DEPEND_API->lp_target_begin; p < DEPEND_API->lp_target_end; p++)

Source: power_manage.h

注册 PMU 硬件操作

芯片 BSP 通过 REGISTER_PHW_DEV_PMU_OPS 将硬件操作集合交给框架:

#define REGISTER_PHW_DEV_PMU_OPS(ops) \
		const struct phw_dev_ops *phw_pmu_ops = &ops
extern const struct phw_dev_ops *phw_pmu_ops;

Source: power_manage.h

睡眠进出回调注入

BSP 与应用的解耦接口——应用可注册自己的回调随系统一起进出休眠:

static void (*sleep_exit_callback_api)(void);

void sleep_set_exit_call_api(void *call_api)
{
    sleep_exit_callback_api = call_api;
}

static void (*sleep_enter_callback_api)(void);

void sleep_set_enter_call_api(void *call_api)
{
    sleep_enter_callback_api = call_api;
}

Source: power_app.c

配置选项

应用层电源配置(app_power_mg.h / app_power_mg.c)

宏/选项类型默认值说明
LVD_WARNING_FOR_LOW_POWERint11:以 LVD 警戒值作为低电警戒线;0:固定 3300mV
LOW_POWER_VOL宏app_power_lvd_warning低电判定电压(LVD 模式取动态值)
LOW_POWER_WARN_VALint240低电告警档位值(预留)
LOW_POWER_OFF_VALint220低电关机档位值(预留)
LOW_POWER_CHECK_INTERVALint2000低电扫描周期(ms)
LOW_POWER_SOFTOFF_TIMEint60000连续低电多久后软关机(ms,60s)
LOW_POWER_SET_MAX_TIMElong4000000显式设置睡眠时长上限(µs)
LOW_POWER_KEEPint-2进入低功耗并一直保持不退出
LOW_POWER_NO_USEint-1传参无效,睡眠时长由蓝牙决定
LOW_POWER_SOFTOFF_BT_EXIT_TIMEint100SOFT_BY_POWER_MODE 下等待蓝牙基带关闭时间(ms)
TCFG_POWER_SUPPLY_MODE编译宏0 (IOVDD)1=VPWR:关机音 2700mV、满电 3700mV;0=IOVDD:2100mV/3000mV
TCFG_SYS_LVD_EN编译宏—使能系统 LVD 检测
TCFG_ADC_VBAT_CH_EN编译宏—使能 VBAT ADC 采样通道
TCFG_LOWPOWER_PATTERN编译宏—SOFT_MODE 直接软关机;SOFT_BY_POWER_MODE 先关蓝牙再进深睡
TCFG_LED_ENABLE编译宏—使能低电 LED 闪烁提示

框架配置(power_manage.h)

选项类型默认值说明
POWER_LIST_SIZEint5电源对象池容量(低功耗路径禁用动态分配)
LOW_POWER_MODE_LIGHT_SLEEPenum1浅睡等级
LOW_POWER_MODE_SLEEPenum2普通睡眠等级
LOW_POWER_MODE_DEEP_SLEEPenum3深睡等级
LOW_POWER_MODE_SOFFenum4软关机等级
LOW_POWER_MODE_EXITenum0x10退出低功耗等级标记

API 参考

void app_power_init(void)

初始化电源管理:初始化 LVD 警戒线、加入 VBAT 采样通道并执行首次采样。在系统上电流程中调用。

u16 app_power_get_vbat(void)

返回最近一次采样的 VBAT 电压(mV)。返回值:电压值,未采样时为 0。

u16 app_power_get_vbat_level(void)

实时读取当前 VBAT 电压(直接调用 gpadc_battery_get_voltage(),不经缓存)。返回值:当前电压(mV)。

u8 app_power_get_vbat_percent(void)

计算电量百分比(0-100)。低于 POWEROFF_TONE_V 返回 0;优先使用弱函数 app_power_remap_vbat_percent() 的映射结果,否则按 (v - POWEROFF_TONE_V) * 100 / (BATTERY_FULL_VALUE - POWEROFF_TONE_V) 线性计算并封顶 100。

void app_power_event_to_user(u8 event)

将电源事件包装为 SYS_DEVICE_EVENT(源为 DEVICE_EVENT_FROM_POWER)投递到应用主循环。参数:event 为 POWER_EVENT_* 枚举值。注意:event_pool_alloc() 失败时丢弃事件并打日志。

int app_power_event_handler(struct device_event *dev, void (*set_soft_poweroff_call)(void))

处理电源设备事件。POWER_EVENT_POWER_LOW 时删除 VBAT 检测定时器并调用软关机回调;POWER_EVENT_POWER_SOFTOFF 直接调用软关机回调。返回:int(当前恒为 false)。

void app_power_vbat_check(void)

以 LOW_POWER_CHECK_INTERVAL 为周期注册 app_power_scan 定时器,开启低电周期检测。

void app_power_set_lvd(u16 lvd_value)

动态设置 LVD 警戒线(即 LOW_POWER_VOL)。

void app_power_set_soft_poweroff(void *priv)

按 TCFG_LOWPOWER_PATTERN 分派软关机:SOFT_MODE 直接调用 power_set_soft_poweroff();SOFT_BY_POWER_MODE 延迟 LOW_POWER_SOFTOFF_BT_EXIT_TIME 后以 LOW_POWER_KEEP 进入深睡。

void p33_io_wakeup_edge(u32 gpio, P33_IO_WKUP_EDGE edge)

配置 P33 唤醒 IO 边沿(由 app_power_mg.h 声明,实现位于 BSP 层)。

框架 API(power_manage.h)

函数说明
u32 low_power_sys_not_idle_cnt(void)非空闲模块计数
u8 low_power_sys_is_idle(void)系统是否可休眠
enum LOW_POWER_LEVEL low_power_level(void)当前低功耗等级
u8 is_low_power_mode(enum LOW_POWER_LEVEL level)是否处于指定等级
void *low_power_get(void *priv, const struct low_power_operation *ops)蓝牙组注册休眠操作
void *low_power_sys_get(void *priv, const struct low_power_operation *ops)系统组注册休眠操作
void low_power_put(void *priv) / low_power_sys_put(void *priv)注销休眠操作
u32 low_power_group_query(struct list_head *request_head)查询组内最短休眠超时
void low_power_suspend(u32 usec) / low_power_resume(u32 usec)蓝牙组挂起/恢复
void low_power_sys_suspend(u32 usec) / low_power_sys_resume(u32 usec)系统组挂起/恢复
u8 low_power_sys_request_enter(u32 timeout) / low_power_sys_request_exit(u32 timeout)系统主动请求进/出低功耗
void deepsleep_target_enter(void) / exit(void) / post(void) / dump(void)遍历深睡注册表执行回调
void sleep_set_enter_call_api(void *call_api) / sleep_set_exit_call_api(void *call_api)注入睡眠进出应用回调

故障模式、边界情况与并发

低电误判与防抖

  • 采样异常:app_power_scan() 对 vol == 0 直接跳过,防止 ADC 未就绪或通道异常时把 0V 误判为"严重低电"。
  • 瞬时跌落:蓝牙发射瞬间 VBAT 可能瞬时低于警戒线,因此必须连续 31 次(约 60s)低于警戒线才触发软关机;电压恢复即清零计数,形成回差,避免频繁开关机。
  • LVD 双保险:LOW_POWER_VOL 在 LVD_WARNING_FOR_LOW_POWER=1 时取 app_power_lvd_warning(比关机电压高 300mV 的动态值),此时 ADC 检测与硬件 LVD 两套机制并行,任一路失效都有兜底。

软关机时序竞争

  • SOFT_BY_POWER_MODE 下,app_power_set_soft_poweroff() 先注册 100ms 延迟任务等待蓝牙基带关闭 ADV/SCAN,随后才 sys_power_down(LOW_POWER_KEEP)。若这 100ms 内又发生按键等事件,soft_by_power_mode() 中的 sys_timeout_del 会清理未处理的 timer,避免双重休眠。
  • app_power_event_handler 在收到 POWER_EVENT_POWER_LOW 时先删 VBAT 检测定时器再关机,保证关机路径不会被打断,也防止唤醒后定时器悬挂。

事件投递失败

app_power_event_to_user() 使用 event_pool_alloc() 分配系统事件;低电场景内存紧张时分配可能失败,此时静默丢弃事件并仅打日志——这是有意的降级策略:宁可丢失一次提示,也不让分配失败导致系统崩溃。

并发与中断上下文约束

  • sleep_enter_callback / sleep_exit_callback 运行在单核、关中断环境(见 power_app.c 注释),禁止打印、禁止耗时操作;串口调试输出仅允许 putchar 单字符。
  • 低功耗路径代码必须放在 .lp_running.bsp.text 段(LP_RUNCODE_AT)常驻 RAM,因为深睡时 Flash 不可访问。
  • 低功耗路径禁用动态内存分配:_power_mem 使用固定数组(POWER_LIST_SIZE=5)管理电源对象池。

电源模式相关边界

  • TCFG_POWER_SUPPLY_MODE 决定 POWEROFF_TONE_V 与 BATTERY_FULL_VALUE,直接影响电量百分比映射。若产品更换供电方式而忘记改此宏,会出现"电量永远 0"或"永不满电"的错误。
  • P3_SFLAG0 ~ P3_SFLAG7 为 SDK 保留(见 power_app.c 的 p33_sfr_save_byte),应用只能使用 P3_SFLAG8 ~ P3_SFLAGB 四个字节保存软关机标志。

性能与运维注意事项

  • 采样开销:VBAT 采样周期 2s,单次采样为阻塞式 GPADC 读取,代价极低;但 app_power_get_vbat_level() 每次都会实时采样,UI 刷屏场景(如常显电量)应改用 app_power_get_vbat() 读取缓存值。
  • 定时器:低电检测定时器由 sys_timer_add 创建,事件处理时显式删除,防止唤醒后重复触发关机流程。
  • 看门狗:从 LOW_POWER_KEEP 深睡唤醒时立即 wdt_init(WDT_8S),保证唤醒序列(BLE 使能、应用恢复)在 8 秒内完成,否则系统被看门狗复位。
  • 调试标记:putchar('{')/('}') 与 putchar('<')/('>') 分别是软关机路径与睡眠路径的串口进出标记,现场定位"是否真的睡着了"可直接抓串口观察这些字符。
  • 温度管理现状:本次已读的电源源码中未发现应用层温度检测/上报实现;AW33N 的 PMU 热保护与充电温度控制由芯片硬件与配置工具承载(参考 post_build/bd57/AW33N_config_tool/conf/source/board/lowpower_v1.lua 及 config 工具的 board 配置),需要在产品侧做温控时,可参考该目录下的板级配置。

扩展点

  1. 低电映射曲线:覆盖弱函数 uint8_t app_power_remap_vbat_percent(uint16_t bat_val),实现锂电池非线性放电曲线;返回 0 表示不覆盖(回退线性映射)。
  2. 唤醒恢复逻辑:覆盖弱函数 void app_to_recover(void),在 SOFT_BY_POWER_MODE 唤醒后执行产品级恢复动作(如重连提示、状态恢复)。
  3. 睡眠进出钩子:调用 sleep_set_enter_call_api() / sleep_set_exit_call_api() 注册应用回调,随系统进出低功耗(如保存/恢复外设状态)。
  4. 模块低功耗注册:新模块通过 REGISTER_LP_TARGET(被动查询)或 REGISTER_LP_REQUEST(主动请求)接入框架仲裁;深睡模块使用 DEEPSLEEP_TARGET_REGISTER。
  5. PMU 硬件操作:更换 PMU 或新增电源域时实现 phw_dev_ops 并用 REGISTER_PHW_DEV_PMU_OPS 注册,框架层无需改动。
  6. LVD 动态调整:运行期调用 app_power_set_lvd() 改变低电警戒线(如不同电池档位)。

测试覆盖观察

  • 低电检测与软关机路径的可测性依赖 TCFG_SYS_LVD_EN 与 TCFG_ADC_VBAT_CH_EN 两个编译开关;关闭任一项时 app_power_scan() 为空操作,便于在无电池硬件时做功能调试。
  • 事件投递失败(event_pool_alloc 返回 NULL)与弱函数默认返回(app_power_remap_vbat_percent 返回 0、app_to_recover 空实现)是源码中显式设计的可替换/可降级点,测试时可通过这些路径验证降级行为。

Related Links

  • app_power_mg.h — 应用层电源管理接口与宏定义
  • app_power_mg.c — 低电检测/软关机实现
  • power_manage.h — 低功耗框架注册表与等级定义
  • power_app.c — 芯片级睡眠/软关回调与电源初始化
  • power_config.c — 板级电源配置
  • power_api.c — 电源 API 封装
  • lib_power_config.c — 库级电源配置
  • power_api.h — 电源 API 头文件
  • lowpower_v1.lua — 配置工具的低功耗板级配置(温度/硬件相关配置入口)
  • bluetooth_powerprofile.lua — 蓝牙功耗配置入口
Prev
存储、参数与时钟
Next
消息、内存与系统配置