当前位置: 首页 > news >正文

【星闪】Hi2821 | 低功耗开发 + 低功耗管理及按键唤醒例程

1. 简介

1.1 低功耗模式

        Hi2821 一共有 3 种低功耗模式——WFI、浅度睡眠和深度睡眠,它们的区别如下:

模式芯片状态特点

WFI

  • CPU停止工作。
  • 部分时钟降频/关闭。
  • 所有中断都能打断这一状态,让CPU继续工作。
  • OsTick正常保持(周期:1ms)。
浅度睡眠
  • CPU不下电,RAM不下电,所有外设可控下电。
  • 只支持部分外设中断唤醒。
  • 蓝牙/星闪广播/连接保持正常。
  • 支持GPIO输出电平保持。
深度睡眠
  • CPU下电,RAM不下电,ULP_GPIO、ULP_WDT以外其他外设下电。
  • 只支持少数外设中断唤醒。
  • 蓝牙/星闪广播/连接保持正常。
  • GPIO输出失效,管脚上下拉正常。
  • osal_timer定时功能正常。
  • 用户自己初始化的外设,唤醒后需自行恢复。

1.2 低功耗条件

        首先,系统中会有一个投票系统(veto),系统初始时否决票数为 0。如果有某个外设或用户调用 uapi_pm_add_sleep_veto 函数,就会投入否决票,此时系统在空闲时只能进入 WFI 模式。如果不存在否决票,那么系统空闲时会关闭 osTimer 并进入浅睡模式;如果进入浅睡的时间超过了深睡的阈值,那么系统将进入深睡模式。

1.3 唤醒源

        浅度睡眠下支持以下唤醒源:

#define PM_LPM_MCPU_CWDT_INT_WAKEUP             14
#define PM_LPM_MCPU_ULP_INT_WAKEUP              13
#define PM_LPM_MCPU_BT_OSC_EN_WAKEUP            12
#define PM_LPM_MCPU_DAP_WAKEUP                  11
#define PM_LPM_MCPU_SSI_WAKEUP                  10
#define PM_LPM_MCPU_GPIO_WAKEUP                 9
#define PM_LPM_MCPU_M_RTC_WAKEUP                8
#define PM_LPM_MCPU_SPI1_INT_WAKEUP             7
#define PM_LPM_MCPU_UART_L1_RX_WAKEUP           6
#define PM_LPM_MCPU_UART_H0_RX_WAKEUP           5
#define PM_LPM_MCPU_UART_L0_RX_WAKEUP           4
#define PM_LPM_MCPU_SPI2_INT_WAKEUP             3
#define PM_LPM_MCPU_QDEC_INT_WAKEUP             2
#define PM_LPM_MCPU_KEYSCAN_INT_WAKEUP          0

        深度睡眠下支持以下唤醒源:

#define PM_LPM_MCPU_WKUP_MASK                   (BIT(PM_LPM_MCPU_CWDT_INT_WAKEUP) | \BIT(PM_LPM_MCPU_ULP_INT_WAKEUP) | \BIT(PM_LPM_MCPU_BT_OSC_EN_WAKEUP) | \BIT(PM_LPM_MCPU_M_RTC_WAKEUP))

1.4 外设下电

外设深睡下电说明唤醒恢复说明
Pinctrl输出模式失能,上下拉和驱动能力正常使用 uapi_pin_set_mode 恢复各个外设的管脚模式
GPIO下电,进入睡眠时 SDK 自动将配置同步到 ULP GPIO用户自行恢复
UART下电SDK 自动恢复(使能 CONFIG_UART_SUPPORT_LPM 宏)
I2C用户自行恢复
ADC用户自行恢复
DMA用户自行恢复
PWM用户自行恢复
WDTSDK 自动恢复(使能 CONFIG_WATCHDOG_SUPPORT_LPM 宏)
TIMERSDK 自动恢复(使能 CONFIG_TIMER_SUPPORT_LPM 宏)
RTCSDK 自动恢复(使能 CONFIG_RTC_SUPPORT_LPM 宏)
SysTickSDK 自动恢复(使能 CONFIG_SYSTICK_SUPPORT_LPM 宏)
TCXOSDK 自动恢复(使能 CONFIG_TCXO_SUPPORT_LPM 宏)
SFCSDK 自动恢复(使能 CONFIG_SFC_SUPPORT_LPM 宏)
SPI用户自行恢复
QDEC用户自行恢复
KEYSCAN用户自行恢复
RAM & Flash不下电
ULP GPIO
ULP RTC
ULP WDT

1.5 低功耗调试

1.5.1 中断和任务

        在 config.py 中添加 OS_DFX_SUPPORT 全局宏定义,主任务会定时打印最近触发的中断号和运行的任务。

使用此功能时确保没有重定义 app_main 函数;如果重定义了,可以通过调用 print_os_task_id_and_name 函数查看系统任务信息,调用 os_dfx_print_info 函数查看最近触发的中断和运行的任务。

1.5.2 工作和空闲时间统计

        在 product_evb_standard.h 中使能 PM_MCPU_MIPS_STATISTICS_ENABLE 宏。

        包含 pm_porting.h 头文件,调用 pm_get_time_before_sleep 函数获取进入睡眠前的时刻;调用 pm_get_total_work_time 函数获取工作的总时间;调用 pm_get_time_after_sleep 函数获取唤醒时的时刻;调用 pm_get_total_work_time 函数获取上一次工作的总时长;调用 pm_get_total_idle_time 获取上一次休眠的总时长。

1.5.3 唤醒原因

        在 product_evb_standard.h 文件中使能 PM_SLEEP_DEBUG_ENABLE 宏。

        唤醒源的的各位说明如下:

  • bit0:较为特殊,一般是由于在睡眠过程中被其他唤醒源唤醒导致,定位原因仍需看其他位;
  • bit1:ulp_gpio;
  • bit2:ulp_rtc(包含任务中的 osal_msleep 行为定时调度和 osal_timer 软调度);
  • bit3:osc_en(和蓝牙业务有关,收发数据前需提前唤醒);
  • bit4:NFC。

1.5.4 VETO投票信息

        包含 pm_veto.h 头文件,调用 uapi_pm_veto_get_info 函数,返回的结构体定义如下:

typedef struct {uint8_t total_counts;uint8_t sub_counts[PM_VETO_ID_MAX];
} pm_veto_counts_t;typedef struct {pm_veto_counts_t veto_counts;uint16_t last_veto_id;uint32_t last_veto_lr;uint64_t veto_timeout_timestamp;
} pm_veto_t;

1.5.5 睡眠信息

        需在 Kconfig 中使能 CONFIG_PM_SLEEP_RECORD_ENABLE。

        包含 pm_sleep.h 头文件,调用 uapi_pm_get_sleep_info 函数,返回的结构体定义如下:

typedef struct sleep_veto {uint16_t last_veto_count;uint16_t last_veto_id;
} sleep_veto_t;typedef struct sleep_event {uint16_t slp_event;uint16_t wkup_event;
} sleep_event_t;typedef struct sleep_history {uint64_t total_slp_time  : 48;uint64_t total_slp_count : 16;
} sleep_history_t;typedef struct sleep_info {uint64_t        sleep_base_time;sleep_veto_t    sleep_veto;sleep_event_t   event;sleep_history_t sleep_history[PM_SLEEP_MAX];
} sleep_info_t;

1.6 Kconfig

  • Power supply by ldo:当主控供电采用 LDO 时使能;
  • Reduce the frequency of low-speed peripgerals:降低低速外设的工作频率至 8MHz,包括TIMER、UART_L0、UART_L1、I2C、KEYSCAN、QDEC;
  • Reduce frequency during wfi:在 WFI 模式下降低外设频率;
  • Enable ultra-deep sleep:使能超级低功耗;
  • Enable the xo fast start:使能外部晶振快速起振;
  • Enable the 32k xo clock:使能外部晶振;
  • Support close ulp-wdt during sleep:睡眠时关闭看门狗;
  • Prevents pin 18/26/27/31 from mis-triggering interrupts during sleep:避免特定管脚在睡眠时的中断误触发。

  • ENABLE SLEEP RECORD:使能睡眠信息记录;
  • ENABLE POWERGATING:使能睡眠掉电功能;
  • VETO ENABLE TRACK:使能 veto 跟踪;
  • The light sleep time threshold:浅睡阈值;
  • The deep sleep time threshold:深睡阈值;
  • Enable wakeup interrupt:使能唤醒中断;
  • Pm sys support:使能低功耗管理任务;

2. 例程

        例程中将配置一个 GPIO 管脚为输入中断,演示低功耗应用中的管脚配置和中断管理。

2.1 代码

#include <stdint.h>#include "app_init.h"
#include "pinctrl.h"
#include "gpio.h"
#include "soc_osal.h"
#include "ulp_gpio.h"
#include "pm_sys.h"#define PM_SAMPLE_GPIO_NUM  2static void pm_gpio_irq_func(pin_t pin, uintptr_t param)
{unused(param);osal_printk("[pm_sys]gpio%d irq.\r\n", pin);uapi_gpio_clear_interrupt(pin);uapi_pm_work_state_reset();
}static void pm_ulpgpio_wkup_handler(uint8_t ulp_gpio)
{uapi_pm_wkup_process(0);osal_printk("ulp_gpio%d wakeup\r\n", ulp_gpio);
}static ulp_gpio_int_wkup_cfg_t g_pm_wk_cfg = {0, PM_SAMPLE_GPIO_NUM, true, ULP_GPIO_INTERRUPT_FALLING_EDGE, pm_ulpgpio_wkup_handler
};static void pm_gpio_slp_cfg(void)
{uapi_gpio_deinit();ulp_gpio_init();ulp_gpio_int_wkup_config(&g_pm_wk_cfg, 1);
}void pm_gpio_wkup_cfg(void)
{ulp_gpio_deinit();uapi_gpio_init();uapi_pin_set_mode(PM_SAMPLE_GPIO_NUM, 0);uapi_pin_set_pull(PM_SAMPLE_GPIO_NUM, PIN_PULL_UP);uapi_gpio_set_dir(PM_SAMPLE_GPIO_NUM, GPIO_DIRECTION_INPUT);uapi_gpio_register_isr_func(PM_SAMPLE_GPIO_NUM, GPIO_INTERRUPT_FALLING_EDGE, pm_gpio_irq_func);
}static int32_t pm_state_work_to_standby(uintptr_t arg)
{unused(arg);uint32_t irq_status = osal_irq_lock();pm_gpio_slp_cfg();osal_irq_restore(irq_status);return 0;
}static int32_t pm_state_standby_to_sleep(uintptr_t arg)
{unused(arg);return 0;
}static int32_t pm_state_standby_to_work(uintptr_t arg)
{unused(arg);uint32_t irq_status = osal_irq_lock();pm_gpio_wkup_cfg();osal_irq_restore(irq_status);return 0;
}static int32_t pm_state_sleep_to_work(uintptr_t arg)
{unused(arg);uint32_t irq_status = osal_irq_lock();pm_gpio_wkup_cfg();osal_irq_restore(irq_status);return 0;
}void pm_low_power_entry(void)
{pm_state_trans_handler_t handler = {.work_to_standby = pm_state_work_to_standby,.standby_to_sleep = pm_state_standby_to_sleep,.standby_to_work = pm_state_standby_to_work,.sleep_to_work = pm_state_sleep_to_work,};uapi_pm_state_trans_handler_register(&handler);uapi_pm_work_state_reset();uapi_pm_set_state_trans_duration(5000, 10000);
}app_run(pm_low_power_entry);void app_main(void *unused)
{(void) unused;#if defined(CONFIG_PINCTRL_SUPPORT_IE)uapi_pin_set_ie(PM_SAMPLE_GPIO_NUM, PIN_IE_1);
#endif /* CONFIG_PINCTRL_SUPPORT_IE */pm_gpio_wkup_cfg();app_tasks_init();
}

1. 初始化 GPIO

        例程中使用的是 IO2 管脚,调用 uapi_pin_set_ie 函数使能管脚输入(如果使能了 CONFIG_PINCTRL_SUPPORT_IE 宏)。

        调用 ulp_gpio_deinit 去初始化 ULP GPIO。

        其余的就是基本的 GPIO 初始化,配置管脚为输入上拉,使能中断,下降沿触发。中断服务函数里面打印管脚号,清除中断位,调用 uapi_pm_work_state_reset 去复位低功耗定时器。

2. 初始化低功耗管理

        调用 uapi_pm_state_trans_handler_register 函数初始化低功耗管理回调,结构体定义如下:

typedef struct pm_state_trans_handler {pm_state_trans_func_t work_to_standby;     /* 工作态转换到待机状态(如interval调大) */pm_state_trans_func_t standby_to_sleep;    /* 工作态转换到深睡状态(如断连、关广播) */pm_state_trans_func_t standby_to_work;     /* 待机态转换到工作状态(如interval调小) */pm_state_trans_func_t sleep_to_work;       /* 深睡态转换到工作状态(如开广播) */
} pm_state_trans_handler_t;

        4 个回调里面的操作都是大同小异的,如果是从低功耗到工作状态就初始化 GPIO,如果是从工作到低功耗状态就初始化 ULP GPIO。

        初始化 ULP GPIO 时,先调用 uapi_gpio_deinit 去初始化 GPIO,再调用 ulp_gpio_init 初始化 ULP GPIO,最后调用 ulp_gpio_int_wkup_config 配置 ULP GPIO 的中断,结构体定义如下:

typedef enum {ULP_GPIO_INTERRUPT_LOW,ULP_GPIO_INTERRUPT_HIGH,ULP_GPIO_INTERRUPT_FALLING_EDGE,ULP_GPIO_INTERRUPT_RISING_EDGE,ULP_GPIO_INTERRUPT_DEDGE
} ulp_gpio_interrupt_t;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;

        中断服务函数里面也是打印管脚号,然后调用 uapi_pm_wkup_process 函数让底层处理唤醒。

        调用 uapi_pm_set_state_trans_duration 函数设置浅睡阈值和深睡阈值,单位毫秒。

2.2 测试

        系统启动后打印 pm_sys_entry 表示低功耗管理任务正在运行。mail.state switch 指示当前切换的低功耗模式,定义如下:

typedef enum pm_state_trans {PM_STATE_WORK_TO_STANDBY    = 0,PM_STATE_STANDBY_TO_SLEEP   = 1,PM_STATE_STANDBY_TO_WORK    = 2,PM_STATE_SLEEP_TO_WORK      = 3,PM_STATE_TRANS_NUM          = 4,
} pm_state_trans_t;

        系统启动后,等待 5 秒后进入浅睡模式;再次等待 5 秒,进入深睡模式;此时将 IO2 接地,ULP_GPIO0 中断触发,芯片切换到工作模式;此时再次将 IO2 接地,现在就是 GPIO2 的中断触发。

http://www.dtcms.com/a/474325.html

相关文章:

  • 怎么做网站的网盘品牌网站建设公司有哪些
  • 【Linux】Socket编程基础
  • 长春建网站wordpress 图片打开慢
  • 91工业设计网模板网站有利于做seo吗
  • 做网站蓝色和什么颜色搭配好看万维网站注册
  • Windows 10 使用 VMware Workstation 搭建 Ubuntu 虚拟机
  • 深入解析Litho的多智能体协同架构与ReAct推理机制
  • 机器视觉---ViBe算法
  • Product Hunt 每日热榜 | 2025-10-12
  • C++11 多线程与并发编程
  • 太原网站建设优化有什么ae做动图的网站
  • 【全志V821_FoxPi】9-3 Linux IIC驱动SSD1306(0.96寸oled屏幕)
  • crm管理系统登录入口官网龙华网站优化
  • 基于S32DS配置S32K344的FlexCAN模块
  • typescript中的难点总结
  • PHP 字符串处理详解
  • 【JUC】线程池有哪些拒绝策略?该如何选择使用?
  • 4 随机数 从一个随机数到另外一个随机数、等概率随机
  • 机器学习17:如何有效使用自监督式学习
  • 生成对抗网络(GAN)及其变种:CycleGAN和StarGAN
  • dede网站地图html文件公司部门撤销要求转岗不同意怎么办
  • 国外购买空间的网站有哪些最优惠的网站优化
  • Linux安装JDK1.8 tomcat MariaDB(MySQL删减版)
  • 【C++】C++中的异常处理try-catch
  • 珠海专业做网站的公司交友软件
  • rclone:安装与配置
  • 第128题 最长连续序列
  • 深度学习》【项目】自然语言处理——情感分析 <上>
  • 在哪里申请网站域名免费制作表白网页
  • 外设模块学习(6)——DHT11温湿度传感器(STM32)