返回首页

Zephyr 电源管理进阶学习笔记

概述

Zephyr RTOS 提供了完整的电源管理(Power Management, PM)框架,支持多种低功耗模式,帮助嵌入式设备最大化电池寿命。本文深入探讨 Zephyr 电源管理的高级特性和实际应用。

电源管理架构

1. 系统架构层次

应用层
    ↓
PM 设备驱动
    ↓
PM 子系统
    ↓
SOC 电源管理
    ↓
硬件低功耗模式

2. 电源状态定义

Zephyr 定义了标准电源状态:

状态名称描述说明
PM_STATE_ACTIVE活动状态CPU 全速运行具体功耗取决于时钟、外设和电压
PM_STATE_RUNTIME_IDLE运行时空闲CPU 空闲但系统仍可快速恢复是否可用依赖 SoC/平台
PM_STATE_SUSPEND_TO_IDLE挂起到空闲比 runtime idle 更深的空闲态平台支持情况不同
PM_STATE_STANDBY待机保留更多上下文,关闭更多模块平台支持情况不同
PM_STATE_SUSPEND_TO_RAM挂起到 RAM以 RAM 保持为前提的更深状态并非所有平台都支持
PM_STATE_SOFT_OFF软关机仅保留唤醒源唤醒后通常视作冷启动

Nordic nRF 电源管理

Nordic 平台说明

Kconfig 配置

基本电源管理配置

# 启用电源管理
CONFIG_PM=y

# 启用设备电源管理
CONFIG_PM_DEVICE=y

# 运行时电源管理
CONFIG_PM_DEVICE_RUNTIME=y

# 更深状态是否可用,取决于当前 SoC/board
# CONFIG_PM_S2RAM=y

Nordic 特定配置

# 低功耗蓝牙配置
CONFIG_BT_LOW_LATENCY=n
CONFIG_BT_CTLR_LOW_LATENCY=n

深度睡眠配置

# 深度睡眠支持
CONFIG_PM_POLICY_APP=y
CONFIG_PM_STATE_LOCK=y

电源管理策略

1. 默认策略

// Zephyr 默认策略:根据空闲时间自动选择状态
// 不需要额外代码,只需启用 CONFIG_PM=y

2. 自定义策略

#include <zephyr/pm/policy.h>

const struct pm_state_info *pm_policy_next_state(uint8_t cpu, int32_t ticks)
{
    ARG_UNUSED(cpu);

    /* 根据当前平台支持的状态集合来选择 */
    if (ticks > k_ms_to_ticks_ceil32(1000)) {
        static const struct pm_state_info state = { PM_STATE_STANDBY, 0, 0 };
        return &state;
    }

    return NULL;
}

设备电源管理

1. 设备电源管理回调

#include <zephyr/pm/device.h>
#include <zephyr/pm/device_runtime.h>

static int my_device_pm_action(const struct device *dev,
                               enum pm_device_action action)
{
    switch (action) {
    case PM_DEVICE_ACTION_SUSPEND:
        // 挂起设备
        break;
    case PM_DEVICE_ACTION_RESUME:
        // 恢复设备
        break;
    case PM_DEVICE_ACTION_TURN_OFF:
        // 关闭设备
        break;
    case PM_DEVICE_ACTION_TURN_ON:
        // 开启设备
        break;
    default:
        return -ENOTSUP;
    }
    return 0;
}

PM_DEVICE_DEFINE(my_device, my_device_pm_action);

DEVICE_DEFINE(my_device, "MY_DEVICE", NULL, 
              PM_DEVICE_REF(my_device), NULL, NULL,
              POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, NULL);

2. 运行时设备电源管理

#include <zephyr/pm/device_runtime.h>

void use_device(const struct device *dev)
{
    // 请求设备(自动恢复)
    pm_device_runtime_get(dev);
    
    // 使用设备...
    
    // 释放设备(可能挂起)
    pm_device_runtime_put(dev);
}

// 在初始化时启用运行时 PM
pm_device_runtime_enable(dev);

低功耗应用模式

1. 事件驱动模式

#include <zephyr/kernel.h>
#include <zephyr/pm/pm.h>

K_SEM_DEFINE(event_sem, 0, 1);

void event_thread(void)
{
    while (1) {
        // 等待事件(自动进入低功耗)
        k_sem_take(&event_sem, K_FOREVER);
        
        // 处理事件
        process_event();
    }
}

// 唤醒源(如 GPIO 中断)
void gpio_isr(const struct device *dev, 
              struct gpio_callback *cb, uint32_t pins)
{
    k_sem_give(&event_sem);
}

2. 周期性唤醒模式

#include <zephyr/kernel.h>

void periodic_task(void)
{
    while (1) {
        // 采集数据
        read_sensors();
        
        // 发送数据
        send_data();
        
        // 休眠 5 分钟(进入低功耗)
        k_sleep(K_MINUTES(5));
    }
}

3. 深度睡眠模式

#include <zephyr/pm/pm.h>
#include <zephyr/pm/policy.h>

void enter_deep_sleep(void)
{
    /* 强制进入某个状态前,要先确认该状态被当前平台支持 */
    pm_state_force(0, &(struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0});
}

唤醒源配置

1. GPIO 唤醒

#include <zephyr/drivers/gpio.h>

#define WAKE_PIN DT_ALIAS(wake_pin)

static const struct gpio_dt_spec wake_pin = GPIO_DT_SPEC_GET(WAKE_PIN, gpios);
static struct gpio_callback wake_cb;

void configure_wake_pin(void)
{
    gpio_pin_configure_dt(&wake_pin, GPIO_INPUT);
    gpio_pin_interrupt_configure_dt(&wake_pin, GPIO_INT_EDGE_RISING);
    gpio_init_callback(&wake_cb, wake_isr, BIT(wake_pin.pin));
    gpio_add_callback(wake_pin.port, &wake_cb);
}

void wake_isr(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
    // 唤醒中断处理
}

2. RTC 唤醒

#include <zephyr/drivers/rtc.h>

void set_rtc_wakeup(uint32_t seconds)
{
    const struct device *rtc = DEVICE_DT_GET(DT_NODELABEL(rtc0));
    struct rtc_time alarm_time;
    
    rtc_get_time(rtc, &alarm_time);
    alarm_time.tm_sec += seconds;
    alarm_time.tm_sec %= 60;
    
    rtc_set_alarm(rtc, &alarm_time, RTC_ALARM_CB_EVERY_SECOND, NULL, NULL);
}

3. BLE 唤醒

# BLE 低功耗配置
CONFIG_BT_CTLR_PM=y
// BLE 连接参数优化功耗
static struct bt_le_conn_param conn_param = {
    .interval_min = 100,  // 100 * 1.25ms = 125ms
    .interval_max = 200,  // 200 * 1.25ms = 250ms
    .latency = 5,         // 从设备延迟
    .timeout = 400,       // 400 * 10ms = 4s
};

bt_conn_le_param_update(conn, &conn_param);

功耗优化技巧

1. 减少唤醒次数

// 差:频繁唤醒
while (1) {
    k_sleep(K_MSEC(100));  // 每秒唤醒 10 次
}

// 好:批量处理
while (1) {
    collect_data();
    k_sleep(K_MINUTES(5));  // 每 5 分钟唤醒一次
}

2. 优化通信间隔

// 蓝牙连接参数
BT_LE_CONN_PARAM(100, 200, 5, 400)  // 更长的间隔 = 更低的功耗

// LTE PSM 模式
CONFIG_LTE_PSM_REQ_RATIO=10  // 请求更长的 PSM 时间

3. 关闭不必要的外设

void enter_low_power(void)
{
    // 关闭 UART
    pm_device_runtime_put(uart_dev);
    
    // 关闭 I2C
    pm_device_runtime_put(i2c_dev);
    
    // 关闭 SPI
    pm_device_runtime_put(spi_dev);
    
    // 降低 CPU 频率
    // Nordic nRF54L 支持动态调频
}

4. 使用低功耗传感器

// 选择低功耗传感器
CONFIG_BME280=y  // BME280 有低功耗模式

// 配置采样率
struct sensor_value odr = { .val1 = 1, .val2 = 0 };  // 1 Hz
sensor_attr_set(dev, SENSOR_CHAN_ALL, SENSOR_ATTR_SAMPLING_FREQUENCY, &odr);

功耗测量

Nordic Power Profiler

// 使用 Nordic Power Profiler Kit (PPK2) 测量功耗
// PPK2 可以精确测量 μA 级别的电流

软件功耗分析

#include <zephyr/kernel.h>

void measure_power_consumption(void)
{
    int64_t start_time, end_time;
    uint32_t start_cycles, end_cycles;
    
    start_time = k_uptime_get();
    start_cycles = k_cycle_get_32();
    
    // 执行任务...
    
    end_time = k_uptime_get();
    end_cycles = k_cycle_get_32();
    
    uint32_t elapsed_cycles = end_cycles - start_cycles;
    int64_t elapsed_ms = end_time - start_time;
    
    printk("Task took %lld ms, %u cycles\n", elapsed_ms, elapsed_cycles);
}

实际案例:低功耗传感器节点

#include <zephyr/kernel.h>
#include <zephyr/pm/pm.h>
#include <zephyr/pm/device_runtime.h>
#include <zephyr/drivers/sensor.h>

#define SLEEP_INTERVAL_S 300  // 5 分钟

static const struct device *bme280 = DEVICE_DT_GET(DT_NODELABEL(bme280));

void low_power_sensor_node(void)
{
    struct sensor_value temp, hum, press;
    int ret;
    
    // 启用设备运行时 PM
    pm_device_runtime_enable(bme280);
    
    while (1) {
        // 请求设备
        pm_device_runtime_get(bme280);
        
        // 读取传感器
        sensor_sample_fetch(bme280);
        sensor_channel_get(bme280, SENSOR_CHAN_AMBIENT_TEMP, &temp);
        sensor_channel_get(bme280, SENSOR_CHAN_HUMIDITY, &hum);
        sensor_channel_get(bme280, SENSOR_CHAN_PRESS, &press);
        
        // 释放设备(进入低功耗)
        pm_device_runtime_put(bme280);
        
        // 发送数据(BLE/LTE)
        send_data(&temp, &hum, &press);
        
        // 进入深度睡眠
        printk("Entering deep sleep for %d seconds...\n", SLEEP_INTERVAL_S);
        k_sleep(K_SECONDS(SLEEP_INTERVAL_S));
    }
}

调试电源管理

启用 PM 日志

CONFIG_PM_LOG_LEVEL_DBG=y
CONFIG_PM_DEVICE_LOG_LEVEL_DBG=y

追踪电源状态

#include <zephyr/pm/pm.h>

void pm_state_notify(uint8_t cpu, struct pm_state_info info)
{
    printk("CPU %d entering PM state: %d\n", cpu, info.state);
}

// 注册通知回调
pm_notifier_register(&notifier);

总结

Zephyr 电源管理关键要点:

  1. 启用 PMCONFIG_PM=yCONFIG_PM_DEVICE=y
  2. 选择策略:默认策略或自定义策略
  3. 配置唤醒源:GPIO、RTC、BLE 等
  4. 优化应用:减少唤醒、批量处理、关闭外设
  5. 测量验证:使用 PPK2 或软件分析

Nordic 特定建议:


*学习日期: 2026-03-21* *小白 🤖*