低功耗管理(Low Power Management)也可以称为功耗管理(Power Management),本⽂档中会简称为PM。

Telink低功耗解惑

        我查阅多连接SDK开发手册时,低功耗管理章节看了两三遍也没太明白,有以下几个问题一直没得以解决,比较困惑,麻烦大神给点指
        进入低功耗好像只有cpu_sleep_wakeup()这个API可以设置进入低功耗的时间,而且还只有200+秒钟,而且只有timer和pad两种唤醒方式;那么

  1. 等到有master发送连接请求了,再退出sleep,等上5秒之后,如果主机还没发送需要的信号,slave又重新进入sleep,如果发送了就不进入sleep,又应该如何设置呢?
  2. 如果想设置更长的睡眠时间怎么设置呢?
  3. 如果用串口唤醒的话,怎么设置呢?
  4. 以及比如下面这情况,是通过cpu_sleep_wakeup()API设置的吗?,通过这个API设置的tick和这里的sleep时间有关吗?这情况和这个API有什么关系呢?

回答:

(1)(4) 在Telink BLE Multiple Connection SDK中,如果当前有BLE任务,广播/扫描/连接,睡眠由BLE stack进行管控,用户不需要介入,但是用户可以在app_process_power_management()使用blc_pm_setSleepMask()配置当前是否暂时关闭sleep,比如当前正在按键或进行OTA。
(3) 如果用串口唤醒的话,建议配置UART_Rx_GPIO为低电平唤醒API cpu_set_gpio_wakeup(),在回调BLT_EV_FLAG_SLEEP_ENTER里将UART_Rx_GPIO配置为GPIO模式,在回调BLT_EV_FLAG_SUSPEND_EXIT里将UART_Rx_GPIO配置为UART模式。

当没有BLE任务(广播关闭/扫描关闭/连接断开),BLE stack不进行睡眠管控,程序在main_loop()循环转,这时用户可以使用API cpu_sleep_wakeup()自行管理睡眠时间,

(2)当期望睡眠时间大于268秒可以使用API cpu_long_sleep_wakeup_32k_rc()自行管理睡眠时间。

如果只打开BLE_APP_PM_ENABLE,协议栈在任务空闲时只会进入suspend。如果同时打开BLE_APP_PM_ENABLE和PM_DEEPSLEEP_RETENTION_ENABLE,协议栈在任务空闲时会进入suspend或deepsleep retention,会根据任务空闲的时间来选择进入哪个睡眠模式,空闲时间长进入deepsleep retention,空闲时间短进入suspend,空闲时间的门限是API blc_pm_setDeepsleepRetentionThreshold()设置的,默认配置为95ms。

注:

对于uart的接收GPIO作为串口唤醒;在回调BLT_EV_FLAG_SUSPEND_ENTER里将UART_Rx_GPIO配置为GPIO模式,在回调BLT_EV_FLAG_SUSPEND_EXIT里将UART_Rx_GPIO配置为UART模式。

bls_app_registerEventCallback(BLT_EV_FLAG_SUSPEND_EXIT, &task_suspend_exit);
bls_app_registerEventCallback(BLT_EV_FLAG_SUSPEND_ENTER, &task_suspend_enter);

在回调函数 task_suspend_exit中UART_Rx_GPIO配置为UART模式,task_suspend_enter中UART_Rx_GPIO配置为GPIO模式。

空闲时间的门限是API blc_pm_setDeepsleepRetentionThreshold()设置的,默认配置为95ms。

这个95ms的值,不是唯一固定的,你要看你的SDK中,power management initialization中,是否有规定了adv和conn的门限值。

低功耗唤醒源

MCU 的suspend/deepsleep/deepsleep retention 在硬件上有2 个唤醒源:TIMER、GPIO PAD。

  • 唤醒源PM_WAKEUP_TIMER 来⾃硬件32k timer(32k RC timer or 32k Crystal timer)。32k timer 在SDK 中已经被正确初始化,user 在使⽤时不需要任何配置,只需要在cpu_sleep_wakeup() 中设置该唤醒源即可。
  • 唤醒源PM_WAKEUP_PAD 来⾃GPIO 模块,除MSPI 4 个管脚外所有的GPIO(PAx/PBx/PCx/PDx)的⾼低电平都具有唤醒功能。

配置GPIO PAD 唤醒sleep mode 的API:
typedef enum{
Level_Low=0,
Level_High =1,
} GPIO_LevelTypeDef;


void cpu_set_gpio_wakeup (GPIO_PinTypeDef pin, GPIO_LevelTypeDef pol, int en);

  1. pin 为GPIO 定义。
  2. pol 为唤醒极性定义:Level_High 表⽰⾼电平唤醒,Level_Low 表⽰低电平唤醒。
  3. en: 1 表⽰enable,0 表⽰disable。

举例说明:
cpu_set_gpio_wakeup (GPIO_PC2, Level_High, 1); //GPIO_PC2 PAD 唤醒打开, ⾼电平唤醒
cpu_set_gpio_wakeup (GPIO_PC2, Level_High, 0); //GPIO_PC2 PAD 唤醒关闭
cpu_set_gpio_wakeup (GPIO_PB5, Level_Low, 1); //GPIO_PB5 PAD 唤醒打开, 低电平唤醒
cpu_set_gpio_wakeup (GPIO_PB5, Level_Low, 0); //GPIO_PB5 PAD 唤醒关闭

低功耗模式的进⼊和唤醒

设置MCU 进⼊睡眠和唤醒的API 为:

int cpu_sleep_wakeup (SleepMode_TypeDef sleep_mode, SleepWakeupSrc_TypeDef wakeup_src, unsigned int wakeup_tick);
  • 第⼀个参数sleep_mode:设置sleep mode,有以下4 个选择,分别表⽰suspend mode、deepsleep mode、deepsleep retention 16K Sram、deepsleep retention 32K Sram。

typedef enum {
SUSPEND_MODE = 0,
DEEPSLEEP_MODE = 0x80,
DEEPSLEEP_MODE_RET_SRAM_LOW16K = 0x43,
DEEPSLEEP_MODE_RET_SRAM_LOW32K = 0x07,
}SleepMode_TypeDef;

  • 第⼆个参数wakeup_src:设置当前的suspend/deepsleep 的唤醒源,参数只能是PM_WAKEUP_PAD、PM_WAKEUP_TIMER 中的⼀个或者多个。如果wakeup_src 为0,那么进⼊低功耗sleep mode 后,⽆法被唤醒。
  • 第三个参数“wakeup_tick”:当wakeup_src 中设置了PM_WAKEUP_TIMER 时,需要设置wakeup_tick来决定timer 在何时将MCU 唤醒。如果没有设置PM_WAKEUP_TIMER 唤醒,该参数⽆意义。

wakeup_tick 的值是⼀个绝对值,按照本⽂档前⾯介绍的System Timer tick 来设置,当System Timer tick 的值达到这个设定的wakeup_tick 后,sleep mode 被唤醒。wakeup_tick 的值需要根据当前的System Timer tick的值,加上由需要睡眠的时间换算成的绝对时间,才可以有效地控制睡眠时间。如果没有考虑当前的SystemTimer tick,直接对wakeup_tick 进⾏设置,唤醒的时间点就⽆法控制。
由于wakeup_tick 是绝对时间,必须在32bit 的System Timer tick 能表⽰的范围之内,所以这个API 能表⽰的最⼤睡眠时间是有限的。⽬前的设计是最⼤睡眠时间为32bit 能表⽰的最⼤System Timer tick 对应时间的7/8。System Timer tick 最⼤能表⽰⼤概268s,那么最⻓sleep 时间时间为268*7/8=234 s,即下⾯delta_Tick不能超过234 s, 若需要更⻓的睡眠时间,user 可以调⽤⻓睡眠函数,具体可参考4.2.7 章节。

cpu_sleep_wakeup(SUSPEND_MODE, PM_WAKEUP_TIMER, clock_time() + delta_tick);
cpu_sleep_wakeup (SUSPEND_MODE , PM_WAKEUP_PAD, 0);
cpu_sleep_wakeup (SUSPEND_MODE , PM_WAKEUP_PAD | PM_WAKEUP_TIMER,
clock_time() + 50* CLOCK_16M_SYS_TIMER_CLK_1MS);

deepsleep mode

cpu_sleep_wakeup (DEEPSLEEP_MODE, PM_WAKEUP_PAD, 0);
cpu_sleep_wakeup (DEEPSLEEP_MODE_RET_SRAM_LOW32K , PM_WAKEUP_TIMER, clock_time() + 8*
↪ CLOCK_16M_SYS_TIMER_CLK_1S);
cpu_sleep_wakeup (DEEPSLEEP_MODE_RET_SRAM_LOW32K , PM_WAKEUP_PAD | PM_WAKEUP_TIMER,clock_time()
↪ + 10* CLOCK_16M_SYS_TIMER_CLK_1S);

低功耗运行流程

  1. no sleep 
    1. 如果没有sleep mode,MCU 的运⾏流程为在while(1) 中循环,反复执⾏“Operation Set A” -        >“Operation Set B”。
  2. suspend   
    1. 如果调⽤cpu_sleep_wakeup 函数进⼊suspend mode,当suspend 被唤醒后,相当于cpu_sleep_wakeup 函数的正常退出,MCU 运⾏到“Operation Set B”。
    2. suspend 是最⼲净的sleep mode,在suspend 期间所有的Sram 数据能保持不变,所有的数字/模拟寄存器状态也保持不变(只有⼏个特殊的例外);suspend 唤醒后,程序接着原来的位置运⾏,⼏乎不需要考虑任何sram和寄存器状态的恢复。suspend 的缺点是功耗偏⾼。
  3. deepsleep
    1. 如果调⽤cpu_sleep_wakeup 函数进⼊deepsleep mode,当deepsleep 被唤醒后,MCU 会重新回到Runhardware bootloader。
    2. 可以看出,deepsleep wake_up 跟Power on 的流程是⼏乎⼀致的,所有的软硬件初始化都得重新做。MCU 进⼊deepsleep 后,所有的Sram 和数字/模拟寄存器(只有⼏个模拟寄存器例外)都会掉电,所以功耗很低,MCU 电流⼩于1uA。
  4. deepsleep retention
    1. 如果调⽤cpu_sleep_wakeup 函数进⼊deepsleep retention mode,当deepsleep retention 被唤醒后,MCU会重新回到Run software bootloader。
    2. deepsleep retention 是介于suspend 和deepsleep 之间的⼀种sleep mode。
    3. suspend 因为要保存所有的sram 和寄存器状态⽽导致电流偏⾼;deepsleep retention 不需要保存寄存器状态,Sram 只保留前16K(或32K)不掉电,所以功耗⽐suspend 低很多,只有2uA 左右。
    4. deepsleep wake_up 后需要把所有的流程重新运⾏⼀遍,⽽deepsleep retention 可以跳过“Run hardware bootloader”这⼀步,这是因为Sram 的前16K(32K)上数据是不丢的,不需要再从flash 上重新拷⻉⼀次。但由于Sram 上retention area 有限,“run software bootloader”⽆法跳过,必须得执⾏;由于deepsleep retention ⽆法保存寄存器状态,所以system initilization 必须执⾏,寄存器的初始化需要重新设置。deepsleep retention wake_up 后的user initilization 可以做⼀些优化改进,和MCU power on/deepsleep wake_up 后的user initilization 做区分处理,参考本⽂档后⾯的介绍。

API

int pm_is_MCU_deepRetentionWakeup(void);

return 值为1,表⽰deepsleep retention wake_up;return 值为0,表⽰power on 或deepsleep wake_up。

void bls_pm_setSuspendMask (u8 mask);
u8 bls_pm_getSuspendMask (void);

mask可以有多个选择

#define SUSPEND_DISABLE 0
#define SUSPEND_ADV BIT(0)
#define SUSPEND_CONN BIT(1)
#define DEEPSLEEP_RETENTION_ADV BIT(2)
#define DEEPSLEEP_RETENTION_CONN BIT(3)

SUSPEND_DISABLE 表⽰sleep disable,不允许MCU 进⼊suspend 和deepsleep retention。

SUSPEND_ADV 和DEEPSLEEP_RETENTION_ADV 分别⽤于控制Advertising state 时MCU 进⼊suspend 和deepsleep retention。

SUSPEND_CONN 和DEEPSLEEP_RETENTION_CONN 分别⽤于控制Conn state Slave role 时MCU 进⼊suspend和deepsleep retention。

SDK 低功耗sleep mode 的设计上,deepsleep retention 是suspend 的替代模式,⽬的是降低sleep mode 的功耗。
以Conn state slave role 为例,SDK ⾸先得看到bltPm.suspend_mask 中SUSPEND_CONN 是否⽣效,才可以进⼊suspend。在可以进⼊suspend 的基础上,根据实际情况再结合bltPm.suspend_mask 中DEEPSLEEP_RETENTION_CONN 是否⽣效,才能决定此时suspend mode 是否被切换为deepsleep retention mode。

所以如果user 希望MCU 进⼊suspend,打开SUSPEND_ADV/SUSPEND_CONN 即可;如果希望MCU 进⼊deepsleep retention mode,必须同时打开SUSPEND_CONN 和DEEPSLEEP_RETENTION_CONN。

该API 最常⽤的3 种情况如下:

bls_pm_setSuspendMask(SUSPEND_DISABLE);

MCU 不允许进⼊sleep mode。

bls_pm_setSuspendMask(SUSPEND_ADV | SUSPEND_CONN);

MCU 在Advertising state 和Conn state Slave role 只允许进⼊suspend,但是不允许进⼊deepsleep retention

bls_pm_setSuspendMask(SUSPEND_ADV | DEEPSLEEP_RETENTION_ADV
|SUSPEND_CONN | DEEPSLEEP_RETENTION_CONN);

MCU 在Advertising state 和Conn state Slave role 允许进⼊suspend 和deepsleep retention,具体进⼊哪种?sleep mode 由当前sleep 的时间⻓度决定。

阈值:

blc_pm_setDeepsleepRetentionThreshold(43, 43);

设置43ms

以⼀个10ms connection interval * (99 + 1) = 1s 的⻓连接为例进⾏说明:

在Conn state slave role 时,由于应⽤层的任务、⼿动latency 的设置等,会导致MCU suspend 时可能出现10ms、20ms、50ms、100ms、1s 等时间值。根据43ms 的阈值设置,MCU 会⾃动将50ms、100ms、1s 等suspend 切换为deepsleep retention,⽽10ms、20ms 等suspend 还是维持suspend,这样的处理可以保证⼀个最优的功耗。

connection latency ⽣效时的Sleep 时序

if(conn_latency != 0)
{latency_use = bls_calculateLatency();T_wakeup = T_brx + (latency_use +1) * conn_interval;
}
else
{T_wakeup = T_brx + conn_interval;
}

当BLE slave 经过connection parameters update(连接参数更新)流程,conn_latency ⽣效后,sleep wake_up的时间为
T_wakeup = T_brx + (latency_use +1) * conn_interval;
下图所⽰为⼀个conn_latency ⽣效时的sleep 时序,此时latency_use= 2。

conn_latency 没有⽣效时,sleep 的时间最⻓不超过1 个connection interval (⼀般都⽐较⼩)。由于conn_latency的⽣效,sleep 的时间可能会出现⼀个⽐较⼤的值,如1s、2s 等,系统功耗可以变得⾮常低。⻓sleep 期间使⽤功耗更⼩的deepsleep retention mode 才变得有意义。

应⽤层定时唤醒

应⽤层定时唤醒API:
void bls_pm_setAppWakeupLowPower(u32 wakeup_tick, u8 enable);

  • wakeup_tick 为定时唤醒的System Timer tick 值;
  • enable 为1 时打开该唤醒功能,enable 为0 时关闭。

以Conn state Slave role 为例:
当user 使⽤bls_pm_setAppWakeupLowPower 设置了应⽤层定时唤醒的app_wakeup_tick,SDK 在进⼊sleep 前,会检查app_wakeup_tick 是否在T_wakeup 之前。

  • 如果app_wakeup_tick 在T_wakeup 之前,如下图所⽰,就会在app_wakeup_tick 触发sleep 提前唤醒;
  • 如果app_wakeup_tick 在T_wakeup 之后,MCU 还是会在T_wakeup 唤醒。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/92136.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/92136.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/92136.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

设备管理系统(MMS)如何在工厂MOM功能设计和系统落地

一、核心系统功能模块设备管理系统围绕设备全生命周期管理设计,涵盖基础数据管理、设备运维全流程管控及统计分析功能,具体如下:基础数据管理设备与备件台账:包含设备台账(设备编号、识别码、型号、生产日期等&#xf…

低空经济展 | 牧羽天航空携飞行重卡AT1300亮相2025深圳eVTOL展

为深入推动低空经济产业高质量发展,构建全球eVTOL(电动垂直起降飞行器)产业交流合作高端平台,2025深圳eVTOL展定于2025年9月23日至25日在深圳坪山燕子湖国际会展中心隆重举办。本届展会以“低空经济・eVTOL・航空应急救援・商载大…

CS231n-2017 Lecture4神经网络笔记

神经网络:我们之前的线性分类器可以接受输入,进而给出评分,这是一种线性变换,再此基础上,我们对这种线性变换结果进行非线性变换,并输入到下一层线性分类器中,这个过程就像是人类大脑神经的运作…

暑期算法训练.5

目录 20. 力扣 34.在排序数组中查找元素的第一个位置和最后一个位置 20.1 题目解析: 20.2 算法思路: 20.3 代码演示: ​编辑 20.4 总结反思: 21.力扣 69.x的平方根 21.1 题目解析: 21.2 算法思路:…

【HDLBits习题详解 2】Circuit - Sequential Logic(5)Finite State Machines 更新中...

1. Fsm1(Simple FSM 1 - asynchronous reset)状态机可分为两类:(1)Mealy状态机:输出由当前状态和输入共同决定。输入变化可能立即改变输出。(2)Moore状态机:输出仅由当前…

多级缓存(亿级流量缓存)

传统缓存方案问题 多级缓存方案 流程 1.客户端浏览器缓存页面静态资源; 2. 客户端请求到Nginx反向代理;[一级缓存_浏览器缓存] 3.Nginx反向代理将请求分发到Nginx集群(OpenResty); 4.先重Nginx集群OpenResty中获取Nginx本地缓存数据;[二级缓存_Nginx本地缓存] 5.若Nginx本地缓存…

浅谈Rust语言特性

如大家所了解的,Rust是一种由Mozilla开发的系统编程语言,专注于内存安全、并发性和高性能,旨在替代C/C等传统系统编程语言。Rust 有着非常优秀的特性,例如:可重用模块 内存安全和保证(安全的操作与不安全的…

React探索高性能Tree树组件实现——react-window、react-vtree

🚀 简介 在现代 Web 应用中,处理大量层级数据的树形结构是一个常见挑战。传统的树组件在面对成千上万个节点时往往会出现性能瓶颈,导致页面卡顿、内存占用过高等问题。本文将深入探讨如何使用 react-window 和 react-vtree 构建高性能的虚拟…

C++ 中的默认构造函数:非必要,不提供

《More Effective C:35个改善编程与设计的有效方法》 读书笔记:非必要不提供default constructor在 C 中,默认构造函数(即无需任何参数即可调用的构造函数)是对象“无中生有”的一种方式。它的核心作用是在没有外部信息…

如何选择低代码开发平台

选择低代码开发平台需要考虑平台的开发效率、灵活性和扩展能力、安全性和合规性、成本效益等关键因素。 具体来说,平台的灵活性和扩展能力尤为重要,这决定了平台是否能长期满足企业日益增长的复杂需求。例如,企业在评估平台时,应关…

电子数据取证领域的双轮驱动——手工分析 vs 自动化分析

在你刚步入电子数据取证领域时,可能很快就注意到一个普遍现象:大多数取证分析师前期都花费大量时间在网上查阅博客、PDF、推文等信息,寻找证据线索的“藏身之处”——例如注册表项、日志文件路径、可疑文件命名模式或远程登录痕迹等。这种信息…

《Python 实时通信全解:掌握 WebSocket 技术与 HTTP 的本质区别》

🚀《Python 实时通信全解:掌握 WebSocket 技术与 HTTP 的本质区别》 引言:通信方式的演进与 Python 的角色 在数字化世界里,**“实时性”**已经成为构建高质量应用的核心诉求。从聊天工具到股票交易系统,再到物联网设备管理——通信的即时响应能力直接决定用户体验。而…

GeoTools 自定义坐标系

前言在GIS开发中,坐标系统是重中之重,在接到任务时首先要确定的就是坐标系。大多数地图库或者互联网地图默认支持WGS84地理坐标系和Web墨卡托投影坐标系。而在我国要求使用自然资源数据使用2000国家大地坐标(CGCS2000)。1. 背景 经…

[特殊字符] Java反射从入门到飞升:手撕类结构,动态解析一切![特殊字符]

【🔍震撼揭秘】 你是否曾想窥探Java类的内部结构?🤔 是否好奇Spring框架如何实现"万物皆可注入"?✨ 本文将带你从反射小白晋升为反射高手,用一行代码透视任意类的构造方法、成员变量和私有方法!&…

CMake与catkin_make的find_package()命令使用说明

在 CMake 中&#xff0c;find_package() 是一个核心函数&#xff0c;用于查找并加载外部依赖库的配置。它的主要作用是定位头文件、库文件&#xff0c;并设置相关变量&#xff0c;以便后续编译和链接。以下是详细解析&#xff1a; 1. 基本语法 find_package(<PackageName&g…

Spring--BeanFactoryPostProcessor的用法

原文网址&#xff1a;Spring--BeanFactoryPostProcessor的用法_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍Spring的BeanFactoryPostProcessor的用法。 BeanPostProcessor和BeanFactoryPostProcessor的区别 项BeanPostProcessorBeanFactoryPostProcessor处理的对象处理…

了解类加载器吗?类加载器的类型有哪些?

一、什么是类加载器&#xff08;ClassLoader&#xff09; 类加载器是 Java 虚拟机中的一部分&#xff0c;负责将 .class 文件加载到 JVM 内存中&#xff0c;生成对应的 Class 对象。 Java 程序中所有的类在使用前都必须通过类加载器加载进 JVM&#xff0c;才能被执行。二、类加…

PHP面向对象高级特性:魔术方法、对象迭代器与设计模式应用

引言 在前一篇文章中,我们探讨了PHP的Traits、匿名类和对象比较机制。本文将深入PHP面向对象编程的更多高级特性,包括魔术方法、对象迭代器以及常用设计模式的实际应用,这些特性能够帮助开发者构建更加灵活和强大的面向对象系统。 魔术方法深度解析 魔术方法是PHP中一组以…

【Java基础】一个月教你轻松掌握Java——第三篇Git

一、Java概述&#xff08;之前的文章&#xff09;二、版本控制工具Git其实这个与Java基础关系不大&#xff0c;但是这个工具还是很重要的&#xff0c;不管是团队之间打比赛还是就业都应该学会它&#xff0c;秉持着学的早一些&#xff0c;用的时间长一点&#xff0c;会更熟练。&…

【C# in .NET】16. 探秘类成员-索引器:通过索引访问对象

探秘类成员-索引器:通过索引访问对象 在 C# 中,索引器(Indexer)是一种独特的类成员,它允许类或结构的实例像数组一样被索引访问,为数据访问提供了极大的灵活性。本文将从基础概念出发,深入.NET 框架底层,剖析索引器的实现机制,并通过实战案例展示其强大的应用价值。 …