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

Telink BLE 低功耗学习

低功耗管理(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.dtcms.com/a/291362.html

相关文章:

  • Vue接口平台学习十一——业务流测试
  • AWS Certified Cloud Practitioner 认证考试总结
  • GoLand安装指南
  • docker 容器学习
  • LeetCode 刷题【10. 正则表达式匹配】
  • CCF-GESP 等级考试 2025年6月认证C++六级真题解析
  • OTA升级失败,端口占用bind: Address already in use
  • 酵母杂交技术解析
  • 微服务项目文档
  • ABeam News | 中野洋辅董事长专访:扎根上海二十载,做中日企业的卓越桥梁
  • 【人工智能99问】什么是教师强制?(16/99)
  • Spring Cache 扩展:Redis 批量操作优化方案与 BatchCache 自定义实现
  • 2130、链表最大孪生和
  • rsync报错解决
  • Shopify 知识点
  • 草木知音的认知进化:Deepoc具身智能如何让除草机读懂花园的呼吸
  • 设备监控之数据处理(1)-概述
  • MQ 核心知识点笔记
  • Android开发中卡顿治理方案
  • 用基础模型构建应用(第十章)AI Engineering: Building Applications with Foundation Models学习笔记
  • 如何用纯 HTML 文件实现 Vue.js 应用,并通过 CDN 引入 Element UI
  • 【PHP 流程控制完全指南】
  • 多端适配灾难现场:可视化界面在PC/平板/大屏端的响应式布局实战
  • .NET依赖注入IOC你了解吗?
  • 开发避坑短篇(3):解决@vitejs plugin-vue@5.0.5对Vite^5.0.0的依赖冲突
  • 万界星空科技锂电池MES解决方案
  • Shell判断结构
  • voice模块
  • 【图论】CF——B. Chamber of Secrets (0-1BFS)
  • 标准文件I/O补充知识