杰理 SDK 文档中心
首页
首页
  • 项目概览

    • AD23N SDK 概述与芯片平台
    • 工程结构与模块划分
  • 快速开始

    • 开发环境搭建与工具链
    • 编译构建指南
    • 烧录与固件升级工具
  • 应用框架与产品工作流

    • 应用入口与模式调度
    • 音乐播放应用
    • MIDI 解码与键盘演奏
    • 录音应用
    • LINEIN 与扩音应用
    • USB 从设备应用
    • 待机、软关机与空闲检测
    • 公共 UI 与 LED 显示
  • 音频子系统

    • 音频解码器框架
    • 音频编码器框架
    • 音效算法库
    • 音频管理与输出通路
  • 存储与文件系统

    • 文件系统层
    • NOR Flash 与虚拟机存储
    • 设备与设备管理
  • 系统服务与运行时

    • 消息机制与事件分发
    • 按键扫描与输入处理
    • 电源管理与低功耗控制
    • 定时器与系统任务
  • 外设驱动与平台

    • CPU 平台与启动流程
    • USB 协议栈与主机/设备驱动
    • SPI 与通用外设接口
  • 固件升级与构建工具

    • 固件升级机制
    • 编译后处理与镜像打包
    • 构建系统与命令行工具

电源管理与低功耗控制

电源管理与低功耗控制是 AD23N 平台 SDK 中负责电池电压监测、低电告警以及系统低功耗模式(pdown/soff/poff)配置与管理的子系统。它由应用层电源管理模块(app_power_mg)与电源库配置模块(lib_power_config)协同构成,为整机提供从"电量感知"到"深度休眠"的完整电源策略支撑。

Purpose and Scope

本文档覆盖 AD23N SDK 中电源管理与低功耗控制相关的完整能力:

  • 应用层电源管理:低电检测(LVD 警告电压 / 固定阈值)、电池电压采样(ADC_CH_PMU_VBAT)、低电告警消息上报(MSG_LOW_POWER)。
  • 电源库配置:pdown(浅睡)/ soff(软关断)/ poff(深度断电)三大低功耗模块的使能开关,以及配套的调试与 PMU 功能开关。
  • 与系统其他模块的交互:升级流程中对低功耗进入的抑制、串口调试在低功耗模式下的保持等。

以下内容属于其他页面范畴,不在本文展开:按键/触摸唤醒的外设驱动细节(见外设驱动相关页面)、ADC 采样底层实现(见 ADC 章节)、具体业务对 MSG_LOW_POWER 消息的业务响应(见应用框架章节)。

Overview

在嵌入式音频/蓝牙 SoC 方案中,电源管理通常分为两个层次:

  1. 电量感知层——通过 ADC 周期性采样电池电压(VBAT),结合 PMU 的 LVD(低压检测)硬件阈值,判断电池是否接近欠压点,并在连续多次采样确认后向系统投递低电告警消息,驱动上层进入省电或关机流程。
  2. 低功耗执行层——由电源库(power_interface)提供 pdown / soff / poff 三种降功耗模式,lib_power_config.c 中的 control_* 开关决定各模式是否被编译/运行进系统,同时提供大量 pdebug_* 调试开关用于定位低功耗进不去、唤醒异常等问题。

app_power_mg.c 是应用层唯一的电源管理入口,对外暴露三个 API:初始化(app_power_init)、周期扫描(app_power_scan)、电压读取(app_power_get_vbat);lib_power_config.c 则是电源库的行为配置中心,所有 control_* / pdebug_* / config_* 常量都以 const 变量形式存在,便于链接期裁剪与运行期调试。

Architecture

flowchart TD
    subgraph sg_App["应用层 (app)"]
        APP["App 主循环 / 任务"]
        APM["app_power_mg<br/>(app_power_init / scan / get_vbat)"]
    end

    subgraph sg_Config["电源库配置 (lib_power_config)"]
        LPC["lib_power_config.c<br/>control_pdown / control_soff / control_poff"]
        DBG["pdebug_* 调试开关"]
        PMU_SW["PMU 功能开关<br/>(reset / wakeup / rtc)"]
    end

    subgraph sg_Drv["底层驱动 / 硬件"]
        ADC["gpadc<br/>ADC_CH_PMU_VBAT"]
        LVD["PMU LVD 低压检测"]
        PI["asm/power_interface.h<br/>pdown / soff / poff 执行"]
    end

    subgraph sg_Sys["系统服务"]
        MSG["消息队列<br/>post_msg"]
        UP["update 升级流程<br/>(抑制 powerdown)"]
    end

    APP -->|"周期调用"| APM
    APM -->|"adc_get_voltage"| ADC
    APM -->|"读 LVD 阈值"| LVD
    APM -->|"连续 10 次低电"| MSG
    MSG -->|"MSG_LOW_POWER"| APP
    LPC -->|"control_* 决定"| PI
    DBG -->|"打印/保持串口"| PI
    PI -->|"进入/退出"| APP
    UP -->|"防止升级中休眠"| PI

架构解读:app_power_mg 是电量感知的前端——它不直接操作 PMU 寄存器,而是复用 ADC 采样通道与 LVD 阈值读取接口;lib_power_config 是低功耗执行的后端开关——它以 const 变量向电源库注入各模式使能状态。两者通过消息(MSG_LOW_POWER)与电源库调用间接耦合,使得应用层无需了解 pdown/soff/poff 的寄存器细节,电源库也无需关心业务何时需要省电。升级模块则通过 REGISTER_LP_TARGET(当前被注释)声明自身在 OTA 期间禁止进入 powerdown,避免升级过程被休眠打断。

低电检测与告警机制

低电检测是电源管理的第一道防线,实现在 sdk/app/bsp/common/power_manage/app_power_mg.c 与 app_power_mg.h 中。其设计目标是在电池电压接近 LVD 欠压点之前提前告警,给应用层留出保存状态、提示用户、主动关机的窗口。

阈值策略:LVD 警告电压 vs 固定阈值

头文件通过编译期宏 LVD_WARNING_FOR_LOW_POWER 选择阈值来源:

#define LVD_WARNING_FOR_LOW_POWER   1//1:使用LVD警告电压作低电提醒 0:使用固定值作低电提醒

#if LVD_WARNING_FOR_LOW_POWER
#define LOW_POWER_VOL		    lvd_warning_voltage
#define LOW_POWER_LOG           "Warning!!! Vbat is near to lvd!\n"
#define low_power_warning_init()  lvd_warning_init()
#else
#define LOW_POWER_VOL		    3300//3.3v
#define LOW_POWER_LOG           "low power\n"
#define low_power_warning_init()
#endif

Source: app_power_mg.h

设计意图:固定阈值(默认 3300mV)简单直接,但不同批次电池、不同 LVD 配置下误差大;LVD 警告电压方案以 PMU 硬件 LVD 阈值为基准,自动跟随硬件配置(软件阈值 = 硬件 LVD 阈值 + 200mV),保证"先于硬件欠压触发告警",避免硬件直接断电导致数据丢失。宏化设计让开发者无需改动逻辑代码即可切换策略。

LVD 阈值读取

get_lvd_vol() 从 PMU 寄存器 P3_VLVD_CON1 的低 3 位读取电压档位,按 1800mV + sel × 100mV 计算:

#define LVD_VOL_MIN     1800
#define LVD_VOL_STEP    100
#define GET_VLVD_VOL_SEL(sel)       (P33_CON_GET(P3_VLVD_CON1) & 0x7)
u32 get_lvd_vol(void)
{
    return (LVD_VOL_MIN + GET_VLVD_VOL_SEL() * LVD_VOL_STEP);
}

Source: app_power_mg.c

注意代码中的 TODO: 后续移回 PMU 注释表明,该函数按规划属于 PMU 驱动层,目前临时放在应用层,属于可重构点(见"扩展点"一节)。lvd_warning_init() 将告警阈值设置为硬件 LVD 电压 + 200mV,并打印实际值与告警值,便于产线/开发调试校准。

周期扫描与去抖

app_power_scan() 采用"连续计数去抖"策略:仅当连续 10 次采样均低于阈值时才上报告警,任何一次高于阈值都会清零计数,有效滤除 ADC 噪声与负载瞬态跌落造成的误报:

void app_power_scan(void)
{
    static u16 low_power_cnt = 0;
    u32 vol = adc_get_voltage(ADC_CH_PMU_VBAT);

    if (-1 != vol) {
        vol = vol * 4;
        if (vol <= LOW_POWER_VOL) {
            low_power_cnt++;
            if (low_power_cnt == 10) {
                log_error(LOW_POWER_LOG);
                post_msg(1, MSG_LOW_POWER);
            }
        } else {
            low_power_cnt = 0;
        }
    }
}

Source: app_power_mg.c

关键细节:

  • 电压换算:ADC 原始电压 ×4 得到真实 VBAT(分压采样比 1:4),与 app_power_get_vbat() 的换算一致。
  • 采样失败保护:adc_get_voltage 返回 -1 时跳过本次判断,避免异常采样值直接触发告警。
  • 消息投递:使用 post_msg(1, MSG_LOW_POWER) 将告警异步投递给系统消息队列,而非同步回调,避免在扫描上下文(通常是被动定时器/轮询)中执行重量级业务逻辑,符合 SDK 的事件驱动架构。
  • 计数上限:low_power_cnt == 10 之后不再继续增长(恒等于 10),因此消息不会重复投递,除非电压回升后计数被清零再下降——这是一个隐式的"迟滞"保护。

初始化与电压读取

void app_power_init(void)
{
    low_power_warning_init();
    adc_add_sample_ch(ADC_CH_PMU_VBAT);
}

u32 app_power_get_vbat(void)
{
    u32 vol = adc_get_voltage(ADC_CH_PMU_VBAT);
    if (-1 != vol) {
        vol *= 4;
    }
    return vol;
}

Source: app_power_mg.c

app_power_init() 在开机早期完成两件事:初始化告警阈值、把 VBAT 通道注册进 ADC 采样轮询表(adc_add_sample_ch),此后 adc_get_voltage 才有有效数据可读。app_power_get_vbat() 供上层随时查询当前电池电压(如电量显示、充电管理)。

核心流程:从采样到告警

sequenceDiagram
    participant APP as App 任务
    participant APM as app_power_mg
    participant ADC as gpadc
    participant PMU as PMU/LVD
    participant MSG as 消息队列
    participant BIZ as 业务模块

    APP->>APM: app_power_init()
    APM->>PMU: get_lvd_vol() 读 P3_VLVD_CON1
    APM->>ADC: adc_add_sample_ch(ADC_CH_PMU_VBAT)
    loop 周期扫描
        APP->>APM: app_power_scan()
        APM->>ADC: adc_get_voltage(ADC_CH_PMU_VBAT)
        ADC-->>APM: 原始电压 (mV/4)
        APM->>APM: vol *= 4, 与 LOW_POWER_VOL 比较
        alt 连续 10 次低于阈值
            APM->>MSG: post_msg(1, MSG_LOW_POWER)
            MSG-->>BIZ: 低电告警事件
            BIZ->>BIZ: 省电/提示/关机策略
        else 电压恢复
            APM->>APM: low_power_cnt = 0 (重新计数)
        end
    end

流程要点:整个低电检测是无阻塞的轮询式设计,不占用独立线程;采样依赖 ADC 后台轮询结果(adc_add_sample_ch 注册后由 ADC 驱动周期性刷新),app_power_scan 只需读取最近一次缓存值,因此可以安全地在任何非关键上下文中调用。告警采用 10 次连续确认 + 消息异步投递的双重保护,兼顾抗噪与解耦。

低功耗模式与电源库配置

低功耗执行层由电源库(asm/power_interface.h 定义接口,SDK 库实现)承担,sdk/app/bsp/common/config/lib_power_config.c 则通过一组 const 变量向电源库注入行为配置。这些变量不是宏,而是真正的全局常量,意味着可以在链接期裁剪(编译器优化掉未引用的分支),也便于在调试器中直接查看/修改。

三大低功耗模式

模式使能开关触发条件功耗等级典型用途
pdown(浅睡)control_pdown由 TCFG_LOWPOWER_LOWPOWER_SEL 非 0 时置 1中系统空闲时进入,保留 RAM,可被按键/定时器快速唤醒
soff(软关断)control_soff恒为 1(注释 //TCFG_LOWPOWER_SOFF)低软件关断大部分外设电源,保留唤醒源
poff(深度断电)control_poff仅当 TCFG_LOWPOWER_LOWPOWER_SEL == DEEP_SLEEP_EN 时置 1极低深度休眠,掉电 RAM,唤醒延迟最大
//使能pdown模块
#if (TCFG_LOWPOWER_LOWPOWER_SEL)
const bool control_pdown = 1;
#else
const bool control_pdown = 0;
#endif

//使能soff模块
const bool control_soff = 1;//TCFG_LOWPOWER_SOFF;

//使能poff模块
#if (TCFG_LOWPOWER_LOWPOWER_SEL==DEEP_SLEEP_EN)
const bool control_poff = 1;
#else
const bool control_poff = 0;
#endif

Source: lib_power_config.c

设计意图:control_soff 恒为 1 且原宏 TCFG_LOWPOWER_SOFF 被注释,说明该平台将 soff 作为默认可用的关断手段;而 pdown/poff 的启用与项目级宏 TCFG_LOWPOWER_LOWPOWER_SEL(定义于 app_config.h 等板级配置)联动——这正是"配置驱动能力"的体现:同一份电源库代码,通过板级配置即可裁剪出不同的低功耗形态。

PMU 功能开关

配置文件还集中管理 PMU 的复位与唤醒模块开关:

//使能复位模块
const bool control_power_reset_mark = 1;
const bool control_power_soft_reset = 1;
const bool control_power_pinr_reset = 1;
const bool control_power_latch_reset = 1;
const bool control_power_reset = 1;
const bool control_power_keep_vcm_reset = 0;

//使能唤醒模块
const bool control_power_wakeup_mark = 1;
const bool control_power_wakeup = 1;

//使能低功耗寄存器检查
const bool control_power_p33_reg_check = 0;

//使能rtc模块
const bool config_rtc_enable = 0;

Source: lib_power_config.c

这些开关决定了电源库在进出低功耗时是否执行对应的寄存器操作(软件复位、引脚复位、锁存复位、唤醒标记、P33 寄存器自检等)。control_power_keep_vcm_reset 与 control_power_p33_reg_check 默认关闭,属于需要明确了解硬件特性后才开启的高级选项——默认关的开关通常意味着"打开会改变复位/检查行为,需硬件配合"。

低功耗调试开关

lib_power_config.c 顶部集中提供了低功耗调试开关,全部默认关闭以避免影响正常功耗:

//调试pdown进不去的场景,影响低功耗流程
const char debug_is_idle = 0;

//出pdown打印信息,不影响低功耗流程
const bool pdebug_pdown_info = 0;

//使能串口调试低功耗,在pdown、soff模式保持串口
const u32 pdebug_uart_lowpower = 0;

//使能串口putbyte调试pdown流程
const bool pdebug_putbyte_pdown = 0;

//使能串口putbyte调试soff流程
const bool pdebug_putbyte_soff = 0;

//使能串口pdown/poff/soff打印所有的寄存器
const bool pdebug_lp_dump_ram = 0;

//使能低功耗耗时检查:1打印执行时间 2执行时间有问题报错
const bool pdebug_reserve_time = 0;

Source: lib_power_config.c

调试开关按影响面分为三类:① 打印信息类(pdebug_pdown_info、pdebug_lp_dump_ram)——不影响流程,可常开;② 保持串口类(pdebug_uart_lowpower、pdebug_putbyte_pdown/soff)——在低功耗模式下维持 UART 输出,会显著增加功耗,仅限开发期;③ 行为影响类(debug_is_idle、pdebug_reserve_time)——会改变低功耗进入判断或耗时检查,用于排查"进不去低功耗"和"进出耗时异常"两类经典问题。文件头注释还提示 debug_is_idle 可打印蓝牙与系统的可进入低功耗时间以及处于 busy 的模块(含 usr_timer 的回调函数地址),是定位"蓝牙已进 sniff 但系统无法休眠"问题的关键工具。

与升级流程的交互

//防止升级过程进入powerdown
/* REGISTER_LP_TARGET(ota_lp_target) = { */

Source: update.c

升级模块通过 REGISTER_LP_TARGET 注册低功耗抑制目标,防止 OTA 过程中系统进入 powerdown 导致升级中断。当前该注册被注释,意味着该平台的升级流程可能依赖其他机制(如升级期间禁止空闲)来保证连续性——这是电源管理与系统服务协作的典型示例:低功耗进入不是单一模块的自治行为,而是多方协商的结果。

配置选项总览

以下表格汇总 lib_power_config.c 与 app_power_mg.h 中的可配置项(均为编译期常量或链接期 const 变量):

配置项类型默认值说明
TCFG_LOWPOWER_LOWPOWER_SEL宏(板级)项目定义低功耗选择:非 0 使能 pdown;DEEP_SLEEP_EN 时使能 poff
LVD_WARNING_FOR_LOW_POWER宏11=LVD 警告电压作低电阈值;0=固定 3300mV
LOW_POWER_VOL宏由策略决定低电告警阈值(LVD 电压+200mV 或 3300mV)
control_pdownconst bool随宏使能 pdown 浅睡模式
control_soffconst bool1使能 soff 软关断模式
control_poffconst bool随宏使能 poff 深度断电模式
control_power_reset*const bool1(keep_vcm 为 0)各类复位模块开关
control_power_wakeup*const bool1唤醒模块开关
control_power_p33_reg_checkconst bool0低功耗进出时 P33 寄存器自检
config_rtc_enableconst bool0RTC 模块使能
debug_is_idleconst char0打印各模块可休眠时间与 busy 状态
pdebug_uart_lowpowerconst u320低功耗模式下保持 UART(耗电)
pdebug_pdown_info / pdebug_putbyte_pdown/soff / pdebug_lp_dump_ram / pdebug_reserve_timeconst bool0各阶段低功耗调试打印/耗时检查

API 参考

电源管理模块对外暴露的接口集中在 app_power_mg.h,共 3 个函数与若干配置宏。

void app_power_init(void)

系统启动早期调用,完成电源管理模块初始化。

行为: 初始化低电告警阈值(LVD 警告电压方案下读取 PMU 档位并 +200mV),并将 VBAT 采样通道 ADC_CH_PMU_VBAT 注册到 ADC 后台采样列表。

参数: 无。

返回: 无。

调用时机: 必须在首次调用 app_power_scan() / app_power_get_vbat() 之前调用;建议放在系统初始化阶段(如 app 初始化流程中)。

Source: app_power_mg.h、app_power_mg.c

void app_power_scan(void)

周期扫描电池电压并检测低电状态。应在定时任务或主循环中周期调用(建议周期不超过 100ms 量级,保证 10 次确认延迟可接受)。

行为: 读取 VBAT 采样值(原始值 ×4 换算),若连续 10 次低于 LOW_POWER_VOL 则 post_msg(1, MSG_LOW_POWER) 投递低电告警;电压回升即清零计数。采样失败(返回 -1)时跳过本次。

参数: 无。

返回: 无。

注意事项: 函数内部使用 static u16 low_power_cnt 保存去抖计数,因此只能存在一个调用者实例,多任务并发调用会破坏去抖逻辑。

Source: app_power_mg.c

u32 app_power_get_vbat(void)

查询当前电池电压(mV)。

行为: 返回 adc_get_voltage(ADC_CH_PMU_VBAT) * 4;采样无效时返回 -1(即 0xFFFFFFFF,调用方需判负)。

参数: 无。

返回: 电池电压(单位 mV);无效采样返回 (u32)-1。

Source: app_power_mg.c

辅助函数与宏

名称类型说明
get_lvd_vol(void)u32读 PMU 硬件 LVD 阈值:1800 + sel*100 mV,sel 取自 P3_VLVD_CON1 低 3 位
lvd_warning_init(void)static void初始化告警阈值 = 硬件 LVD + 200mV 并打印
LOW_POWER_VOL宏低电告警阈值(策略相关,见上文)
LOW_POWER_LOG宏低电触发时的日志字符串
MSG_LOW_POWER系统消息低电告警消息,由 post_msg(1, ...) 投递

使用示例

示例 1:电源管理初始化与周期扫描(标准接入方式)

以下代码展示了 app_power_mg 的标准接入模式——初始化注册采样通道,随后在系统定时扫描流程中周期调用 app_power_scan():

void app_power_init(void)
{
    low_power_warning_init();
    adc_add_sample_ch(ADC_CH_PMU_VBAT);
}

void app_power_scan(void)
{
    static u16 low_power_cnt = 0;
    u32 vol = adc_get_voltage(ADC_CH_PMU_VBAT);

    if (-1 != vol) {
        vol = vol * 4;
        if (vol <= LOW_POWER_VOL) {
            low_power_cnt++;
            if (low_power_cnt == 10) {
                log_error(LOW_POWER_LOG);
                post_msg(1, MSG_LOW_POWER);
            }
        } else {
            low_power_cnt = 0;
        }
    }
}

Source: app_power_mg.c

示例 2:读取当前电池电压

业务模块(如电量显示、充电管理)可通过 app_power_get_vbat() 获取实时电压:

u32 app_power_get_vbat(void)
{
    u32 vol = adc_get_voltage(ADC_CH_PMU_VBAT);
    if (-1 != vol) {
        vol *= 4;
    }
    return vol;
}

Source: app_power_mg.c

调用方需要注意返回值 -1 的判负处理(ADC 尚未就绪或采样异常),避免将异常值当作真实电压显示。

示例 3:低功耗使能的板级配置联动

项目板级配置通过 TCFG_LOWPOWER_LOWPOWER_SEL 决定哪些低功耗模式生效,电源库配置据此生成对应的 control_* 常量:

//使能pdown模块
#if (TCFG_LOWPOWER_LOWPOWER_SEL)
const bool control_pdown = 1;
#else
const bool control_pdown = 0;
#endif

//使能poff模块
#if (TCFG_LOWPOWER_LOWPOWER_SEL==DEEP_SLEEP_EN)
const bool control_poff = 1;
#else
const bool control_poff = 0;
#endif

Source: lib_power_config.c

这是一种"零代码改动"的功耗形态裁剪方式:同一 SDK 二进制工程,仅调整板级宏即可在"仅 soff""pdown+soff""pdown+soff+poff"等形态间切换。

失败模式、边界情况与并发

低电误报与漏报

  • ADC 噪声 / 负载瞬态:app_power_scan 的"连续 10 次低于阈值才告警"去抖机制是主要防线。任何一次采样高于阈值都会清零 low_power_cnt,因此瞬时跌落(如射频发射瞬间、电机启动)不会触发告警。若实际产品仍存在误报,应优先检查 ADC 采样周期是否过慢导致 10 次确认时间过长,或阈值余量(+200mV)是否不足。
  • 漏报风险:告警只在 low_power_cnt == 10 时投递一次,之后计数恒为 10 不再重复投递。若电压在临界值附近反复震荡(低于阈值→高于阈值→低于阈值),每次回升都会清零计数,可能长时间不触发告警——这是"迟滞"设计的有意取舍:宁可少报一次,也不在临界区反复轰炸业务层。对必须保证告警的场景,业务层应在收到 MSG_LOW_POWER 后主动进入省电状态而非等待再次告警。

采样无效值处理

adc_get_voltage 返回 -1 表示采样无效(通道未注册、ADC 忙、首次采样未完成等)。app_power_scan 与 app_power_get_vbat 均做了判负保护,但返回值语义不同:

  • app_power_scan:跳过本次判断,不改变去抖计数(既不 ++ 也不清零),静默容忍偶发失败。
  • app_power_get_vbat:将 -1 原样返回(以 u32 形式即 0xFFFFFFFF),调用方必须判负,否则会把一个极大的电压值当作真实电量。这是该 API 最容易踩的坑。

并发与重入

  • app_power_scan 使用函数级 static 去抖计数器,隐式要求单实例、单调用者。若多个任务同时调用,计数互相干扰会导致去抖逻辑失效。建议固定由一个定时任务/扫描循环调用。
  • 消息投递 post_msg(1, MSG_LOW_POWER) 本身是异步的,可安全地在中断/任务上下文调用,但业务对消息的处理应放在消息循环中,避免在低优先级上下文阻塞。
  • lib_power_config.c 中的 control_* / pdebug_* 为 const 全局变量,运行期不可变;修改需重新编译。若需在运行时动态切换低功耗模式,应通过电源库提供的运行时接口(power_interface),而非改动这些常量。

低功耗进不去 / 唤醒异常的典型排查

配置文件头部注释给出了官方调试路径:debug_is_idle = 1 可打印蓝牙与系统各自可进入低功耗的时间(msec),并打印当前处于 busy 的模块——若蓝牙已进入 sniff 而系统仍无法休眠,通常是 usr_timer 等模块 busy,打印会给出对应回调函数地址。pdebug_reserve_time 可检查进出低功耗耗时,定位"唤醒慢/休眠慢"。pdebug_uart_lowpower 在 pdown/soff 下保持串口,配合 pdebug_lp_dump_ram 可在休眠现场 dump 寄存器,但这些开关会显著增加功耗,严禁在量产固件中开启。

升级与休眠互斥

OTA 升级期间若系统进入 powerdown 会导致升级中断、固件损坏。update.c 中 REGISTER_LP_TARGET(ota_lp_target) 被注释,表明当前版本未通过该机制显式抑制休眠——因此升级流程必须依赖其他保证(如升级期间禁止系统进入 idle 或升级任务占用电源锁)。若在升级场景出现"升级中断/失败"问题,应优先核查升级流程是否持有电源管理锁或等效机制。

性能与运维注意事项

  • 功耗:低电检测本身几乎零功耗(复用 ADC 后台采样 + 周期读取),但调试开关(pdebug_uart_lowpower 等)会在休眠态保持 UART,量产固件必须全部置 0。
  • 时序:去抖的 10 次确认 × 扫描周期 = 告警最迟延迟。若扫描周期为 100ms,最迟约 1s 后告警;需更快响应(如避免硬件 LVD 直接断电)时应缩短扫描周期或降低确认次数(改动需评估抗噪)。
  • 启动顺序:app_power_init 必须在扫描前调用,否则 adc_get_voltage 返回 -1,告警永远不触发(静默失效)。建议把初始化放在系统电源/外设初始化阶段,把扫描放在与按键扫描同级的周期任务中。
  • ADC 换算一致性:×4 的换算因子隐含了硬件分压比(1:4),若硬件改版更换分压电阻,必须同步修改 app_power_scan 与 app_power_get_vbat 两处,避免"显示电压与告警电压不一致"的隐蔽 bug。

扩展点

  1. 阈值策略扩展:app_power_mg.h 中的 LVD_WARNING_FOR_LOW_POWER 宏提供两档策略(LVD 跟随 / 固定值)。若需更复杂的策略(如温度补偿、倍率曲线),可仿照现有宏体系扩展,核心改动集中在 lvd_warning_init() 与 LOW_POWER_VOL 的定义处。
  2. get_lvd_vol() 回归 PMU 驱动:源码注释 TODO: 后续移回 PMU 表明该函数应归属 PMU 驱动层;重构时将其迁入 PMU 模块并在应用层保持调用接口不变,即可隔离硬件细节。
  3. 低功耗模式裁剪:通过板级宏 TCFG_LOWPOWER_LOWPOWER_SEL 即可启用/禁用 pdown、poff;新增低功耗形态(如 retention 模式)只需在 lib_power_config.c 增加对应的 control_* 常量并接入电源库。
  4. 低电告警的业务响应:MSG_LOW_POWER 是标准消息事件,业务层可自由注册处理:音量提示、LED 指示、自动保存、限时关机等,无需改动电源管理模块本身——事件驱动设计保证了电源层与业务层的解耦。
  5. 低功耗抑制目标:REGISTER_LP_TARGET 机制(见 update.c 注释示例)可用于注册"禁止进入低功耗"的模块,适合 OTA、校准等不可中断流程。

测试情况

源码中未发现针对电源管理模块的独立单元测试文件;现有验证手段以编译期配置检查和运行时日志为主:

  • 配置有效性通过条件编译保证(TCFG_LOWPOWER_LOWPOWER_SEL 与 control_pdown/poff 联动)。
  • 运行时通过 log_error(LOW_POWER_LOG) 输出低电告警,lvd_warning_init 打印告警阈值与硬件 LVD 实际值,便于产线与开发校准。
  • 低功耗进出时序问题依赖 pdebug_reserve_time、debug_is_idle 等调试开关人工验证。

建议新增测试方向:① 阈值边界(恰好等于/略高于/略低于 LOW_POWER_VOL);② 去抖逻辑(连续 9 次低电 + 1 次回升不应告警,连续 10 次应告警且不重复);③ 采样失败(返回 -1)时的行为;④ app_power_get_vbat 判负处理。

Related Links

  • app_power_mg.c — 应用层电源管理实现
  • app_power_mg.h — 电源管理 API 与阈值策略定义
  • lib_power_config.c — 电源库配置与低功耗调试开关
  • update.c — 升级流程与低功耗抑制的交互示例
  • 相关目录项:低功耗模式(pdown/soff/poff)的底层寄存器实现见"PMU 驱动"页面;MSG_LOW_POWER 消息的业务处理见"应用框架与消息机制"页面;ADC 采样实现见"ADC 采样"页面。
Prev
按键扫描与输入处理
Next
定时器与系统任务