Files
system-design/software-copyright/12-writech-pen-firmware/power/power_manager.c
T
2026-03-22 15:24:40 +08:00

293 lines
7.9 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 自然写智能点阵笔嵌入式固件软件 V1.0
* power_manager.c - 电源管理模块
*
* 功能说明:
* 1. 低功耗状态机管理(Active/LightSleep/DeepSleep
* 2. 各外设电源域控制
* 3. 唤醒源配置与管理
* 4. 功耗统计与优化
*/
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "hal_gpio.h"
#include "hal_rtc.h"
/* ========== 电源域定义 ========== */
#define POWER_DOMAIN_CAMERA (1 << 0) /* 摄像头 */
#define POWER_DOMAIN_BLE (1 << 1) /* BLE模块 */
#define POWER_DOMAIN_FLASH (1 << 2) /* 外部Flash */
#define POWER_DOMAIN_SENSOR (1 << 3) /* 压力传感器 */
#define POWER_DOMAIN_LED (1 << 4) /* LED指示灯 */
#define POWER_DOMAIN_ALL 0xFF
/* ========== 唤醒源定义 ========== */
#define WAKEUP_SRC_PEN_TIP (1 << 0) /* 笔尖接触 */
#define WAKEUP_SRC_BUTTON (1 << 1) /* 按键 */
#define WAKEUP_SRC_CHARGER (1 << 2) /* 充电器插入 */
#define WAKEUP_SRC_RTC (1 << 3) /* RTC定时唤醒 */
#define WAKEUP_SRC_BLE (1 << 4) /* BLE连接事件 */
/* ========== 功耗模式参数 ========== */
/* 轻度睡眠时的CPU频率(MHz) */
#define LIGHT_SLEEP_FREQ_MHZ 16
/* 正常工作CPU频率(MHz */
#define ACTIVE_FREQ_MHZ 168
/* RTC唤醒间隔(秒) - 用于周期性电量检查 */
#define RTC_WAKEUP_INTERVAL_S 60
/* ========== 静态变量 ========== */
/* 当前活跃的电源域 */
static uint8_t s_active_domains = POWER_DOMAIN_ALL;
/* 当前唤醒源配置 */
static uint8_t s_wakeup_sources = 0;
/* 功耗统计 */
static uint32_t s_active_time_ms = 0;
static uint32_t s_sleep_time_ms = 0;
/* ========== 电源管理初始化 ========== */
/**
* 初始化电源管理模块
* 配置各电源域控制GPIO,设置默认唤醒源
*/
void power_manager_init(void) {
/* 配置电源控制GPIO */
hal_gpio_config_output(GPIO_CAMERA_POWER);
hal_gpio_config_output(GPIO_FLASH_POWER);
hal_gpio_config_output(GPIO_SENSOR_POWER);
hal_gpio_config_output(GPIO_LED_POWER);
/* 默认所有电源域开启 */
s_active_domains = POWER_DOMAIN_ALL;
/* 默认唤醒源:笔尖触摸 + 充电器 + 按键 */
s_wakeup_sources = WAKEUP_SRC_PEN_TIP | WAKEUP_SRC_CHARGER | WAKEUP_SRC_BUTTON;
/* 初始化功耗统计 */
s_active_time_ms = 0;
s_sleep_time_ms = 0;
}
/* ========== 电源域控制 ========== */
/**
* 使能指定电源域
* @param domain_mask 电源域掩码
*/
void power_domain_enable(uint8_t domain_mask) {
if (domain_mask & POWER_DOMAIN_CAMERA) {
hal_gpio_write(GPIO_CAMERA_POWER, 1);
}
if (domain_mask & POWER_DOMAIN_FLASH) {
hal_gpio_write(GPIO_FLASH_POWER, 1);
}
if (domain_mask & POWER_DOMAIN_SENSOR) {
hal_gpio_write(GPIO_SENSOR_POWER, 1);
}
if (domain_mask & POWER_DOMAIN_LED) {
hal_gpio_write(GPIO_LED_POWER, 1);
}
s_active_domains |= domain_mask;
}
/**
* 禁用指定电源域
* @param domain_mask 电源域掩码
*/
void power_domain_disable(uint8_t domain_mask) {
if (domain_mask & POWER_DOMAIN_CAMERA) {
hal_gpio_write(GPIO_CAMERA_POWER, 0);
}
if (domain_mask & POWER_DOMAIN_FLASH) {
hal_gpio_write(GPIO_FLASH_POWER, 0);
}
if (domain_mask & POWER_DOMAIN_SENSOR) {
hal_gpio_write(GPIO_SENSOR_POWER, 0);
}
if (domain_mask & POWER_DOMAIN_LED) {
hal_gpio_write(GPIO_LED_POWER, 0);
}
s_active_domains &= ~domain_mask;
}
/* ========== 低功耗状态转换 ========== */
/**
* 进入轻度睡眠模式
* - 降低CPU频率到16MHz
* - 关闭摄像头和传感器电源域
* - 保持BLE连接和Flash电源
* - 可由笔尖触摸或BLE事件唤醒
*/
void power_enter_light_sleep(void) {
/* 关闭不必要的电源域 */
power_domain_disable(POWER_DOMAIN_CAMERA | POWER_DOMAIN_SENSOR | POWER_DOMAIN_LED);
/* 降低CPU频率 */
SystemClock_SetFrequency(LIGHT_SLEEP_FREQ_MHZ);
/* 配置唤醒源 */
hal_gpio_set_wakeup(GPIO_PEN_TIP_PIN, GPIO_WAKEUP_RISING);
hal_gpio_set_wakeup(GPIO_BUTTON_PIN, GPIO_WAKEUP_FALLING);
/* 进入CPU SLEEP模式(WFI等待中断) */
__WFI();
/* 唤醒后恢复 */
SystemClock_SetFrequency(ACTIVE_FREQ_MHZ);
power_domain_enable(POWER_DOMAIN_SENSOR | POWER_DOMAIN_LED);
}
/**
* 进入深度睡眠模式
* - 关闭所有外设电源域
* - 断开BLE连接
* - MCU进入STOP/STANDBY模式
* - 仅保留RTC和GPIO唤醒
* - 唤醒后相当于系统复位重启
*/
void power_enter_deep_sleep(void) {
/* 保存关键数据到Flash */
save_power_state();
/* 关闭所有电源域 */
power_domain_disable(POWER_DOMAIN_ALL);
/* 配置RTC唤醒(定时检查电量) */
hal_rtc_set_alarm(RTC_WAKEUP_INTERVAL_S);
/* 配置GPIO唤醒源 */
hal_gpio_set_wakeup(GPIO_PEN_TIP_PIN, GPIO_WAKEUP_RISING);
hal_gpio_set_wakeup(GPIO_USB_DETECT_PIN, GPIO_WAKEUP_RISING);
hal_gpio_set_wakeup(GPIO_BUTTON_PIN, GPIO_WAKEUP_FALLING);
/* 进入STANDBY模式(最低功耗,唤醒后从头执行) */
hal_enter_standby_mode();
}
/* ========== 功耗状态保存/恢复 ========== */
/* Flash中保存电源状态的地址 */
#define POWER_STATE_FLASH_ADDR 0x0000F000
/* 电源状态保存结构 */
typedef struct {
uint32_t magic; /* 魔数 0xPWR55AA */
uint32_t total_active_ms; /* 累计活跃时长 */
uint32_t total_sleep_ms; /* 累计睡眠时长 */
uint32_t boot_count; /* 启动次数 */
uint32_t last_shutdown_reason; /* 上次关机原因 */
uint32_t checksum; /* CRC校验 */
} PowerStateFlash;
/**
* 保存电源状态到Flash
* 在进入深度睡眠前调用
*/
static void save_power_state(void) {
PowerStateFlash state;
state.magic = 0x50575200; /* "PWR\0" */
state.total_active_ms = s_active_time_ms;
state.total_sleep_ms = s_sleep_time_ms;
state.boot_count = 0; /* 将在恢复时递增 */
state.last_shutdown_reason = 0;
/* 计算校验和 */
uint32_t sum = 0;
const uint32_t *data = (const uint32_t *)&state;
uint8_t i;
for (i = 0; i < (sizeof(state) / 4) - 1; i++) {
sum ^= data[i];
}
state.checksum = sum;
/* 写入Flash */
hal_flash_erase_sector(POWER_STATE_FLASH_ADDR);
hal_flash_write(POWER_STATE_FLASH_ADDR, (const uint8_t *)&state, sizeof(state));
}
/**
* 从Flash恢复电源状态
* 在启动时调用
*/
void power_restore_state(void) {
PowerStateFlash state;
hal_flash_read(POWER_STATE_FLASH_ADDR, (uint8_t *)&state, sizeof(state));
if (state.magic != 0x50575200) {
/* 无有效的保存数据 */
return;
}
/* 验证校验和 */
uint32_t sum = 0;
const uint32_t *data = (const uint32_t *)&state;
uint8_t i;
for (i = 0; i < (sizeof(state) / 4) - 1; i++) {
sum ^= data[i];
}
if (sum != state.checksum) {
return; /* 数据损坏 */
}
/* 恢复功耗统计 */
s_active_time_ms = state.total_active_ms;
s_sleep_time_ms = state.total_sleep_ms;
}
/* ========== 功耗统计接口 ========== */
/**
* 更新活跃时间统计
* @param elapsed_ms 经过的毫秒数
*/
void power_update_active_time(uint32_t elapsed_ms) {
s_active_time_ms += elapsed_ms;
}
/**
* 更新睡眠时间统计
* @param elapsed_ms 经过的毫秒数
*/
void power_update_sleep_time(uint32_t elapsed_ms) {
s_sleep_time_ms += elapsed_ms;
}
/**
* 获取累计活跃时长(秒)
*/
uint32_t power_get_active_seconds(void) {
return s_active_time_ms / 1000;
}
/**
* 获取电源效率(活跃时间占比百分比)
*/
uint8_t power_get_efficiency(void) {
uint32_t total = s_active_time_ms + s_sleep_time_ms;
if (total == 0) return 100;
return (uint8_t)((uint64_t)s_active_time_ms * 100 / total);
}
/**
* 获取当前活跃的电源域掩码
*/
uint8_t power_get_active_domains(void) {
return s_active_domains;
}