学习BLE已有一段时间,从开始时的一片空白到现在的略有领悟。下面来讲讲鄙人学习BLE中的一些领悟。

用BLE的人都知道,BLE的最大亮点是低功耗,实现低功耗的主要方式就是CC2540/CC2541的休眠机制。

休眠的模式主要分为PM2和PM3两种模式(另一种PM1模式,是用于低于3ms时间的休眠,几乎不用)。唤醒方式主要分为ST睡眠定时器唤醒和外部中断唤醒。唤醒方式和休眠模式的对应关系为:PM2模式是由ST睡眠定时器唤醒,PM3模式是有外部中断唤醒。

许多开发者都想在不用BLE的时候让其进入最低功耗模式:PM3模式,但是在debug程序的时候,发现CC2540工程里的休眠函数都是进入PM2模式的,无法让其自己进入PM3模式。于是,有许多人就想直接编程电源寄存器,让其强行进入PM3。这样的方法是可以达到进入PM3模式,但如果你没有处理好休眠前的现场保护和唤醒后的恢复工作,是会出现溢出,唤醒后程序跑飞的危险,这样反而不会降低功耗的,吃力不讨好。

其实,TI的休眠处理函数已经处理得很好了,只要你掌握了它的休眠机制,你照样可以对其调配自如。下面是我总结的一些浅见。

一、CC2540 or CC2541进入PM3深度休眠的条件

①osal_timeout = 0;

②llTimeout = 0;

只要同时满足上面两个条件,BLE就会自己进入PM3模式,此时,所有内部电路都关闭,只有外部中断和复位电路可以工作,因此,功耗最低,且可通过外部中断对其唤醒。当中的一个不为0,都将进入PM2模式。

下面肯定会有人问上面这两个条件是什么,osal_timeout就是各层的定时事件的某个事件的超时时间,llTimeout是link layer最底层,也就是RF控制器层的定时事件的超时时间。只要其中的一个不等于0,就说明有定时事件存在,需要定时来处理这些事件,因此就需要定时来唤醒芯片来执行这些事件,所以芯片就不能进入PM3(PM3只能是外部中断唤醒),只能进入PM2模式。

所以,也就是说,要想进入PM3模式,就必须清空所有的定时事件,当不存在任何的定时事件时,即osal_timeoout和llTimeout都会为0,这样就直接导致进入PM3模式。清理定时事件,就是深度休眠的前处理。如此,使得整个BLE有良好的鲁棒性。下面从代码的角度来剖析BLE的休眠机制。

二、BLE的休眠函数

下面就是休眠处理函数的源码,里面timeout就是要设置休眠定时器的时间,这个值来自于osal_timeout或者是llTimeout,那个值小,就说明那个事件更紧急,则由小的来赋给timeout设置休眠定时器,执行定时任务。当timeout = 0时,说明没有定时任务了,就可进入PM3深度休眠了。

llTimeout是通过LL_TimeToNextRfEvent( &sleepTimer, &llTimeout )来得到底层的定时事件,LL_TimeToNextRfEvent( &sleepTimer, &llTimeout )函数是link layer的不开源的代码,因此看不到里面的细节,但是可以肯定的是,llTimeout是和RF定时控制事件相关。一般蓝牙广播、连接、初始化,此llTImeout的值就不会为零,当没有广播、断开连接可以使得llTImeout为零。

osal_timeout一般为应用层的定时事件,由osal_start_timeEX(task_id, event, timeout)设定的定时,只要用相应的osal_stop_timeEX( task_id, event )终止所有的事件,就可以使得osal_timeout为零。

void halSleep( uint32 osal_timeout )
{uint32 timeout;uint32 llTimeout;uint32 sleepTimer;// max allowed sleep time in msif (osal_timeout > MAX_SLEEP_TIMEOUT){osal_timeout = MAX_SLEEP_TIMEOUT;}// get LL timeout value already converted to 32kHz ticksLL_TimeToNextRfEvent( &sleepTimer, &llTimeout );// check if no OSAL timeout// Note: If the next wake event is due to an OSAL timeout, then wakeForRF//       will already be FALSE, and the call to LL_TimeToNExtRfEvent will//       already have taken a snapshot of the Sleep Timer.if (osal_timeout == 0){// use common variabletimeout = llTimeout;// check if there's time before the next radio event// Note: Since the OSAL timeout is zero, then if the radio timeout is//       not zero, the next wake (if one) will be due to the radio event.wakeForRF = (timeout != 0) ? TRUE : FALSE;}else // OSAL timeout is non-zero{// convet OSAL timeout to sleep time// Note: Could be early by one 32kHz timer tick due to rounding.timeout = HAL_SLEEP_MS_TO_32KHZ( osal_timeout );// so check time to radio event is non-zero, and if so, use shorter valueif ((llTimeout != 0) && (llTimeout < timeout)){// use common variabletimeout = llTimeout;// the next ST wake time is due to radiowakeForRF = TRUE;}else // OSAL timeout will be used to wake{// so take a snapshot of the sleep timer for sleep based on OSAL timeoutsleepTimer = halSleepReadTimer();// the next ST wake time is not due to radiowakeForRF = FALSE;}}// HAL_SLEEP_PM3 is entered only if the timeout is zerohalPwrMgtMode = (timeout == 0) ? HAL_SLEEP_DEEP : HAL_SLEEP_TIMER;// check if sleep should be enteredif ( (timeout > PM_MIN_SLEEP_TIME) || (timeout == 0) ){halIntState_t ien0, ien1, ien2;HAL_ASSERT( HAL_INTERRUPTS_ARE_ENABLED() );HAL_DISABLE_INTERRUPTS();// check if radio allows sleep, and if so, preps system for shutdownif ( LL_PowerOffReq(halPwrMgtMode) == LL_SLEEP_REQUEST_ALLOWED ){
#if ((defined HAL_KEY) && (HAL_KEY == TRUE))// get peripherals ready for sleepHalKeyEnterSleep();
#endif // ((defined HAL_KEY) && (HAL_KEY == TRUE))#ifdef HAL_SLEEP_DEBUG_LEDHAL_TURN_OFF_LED3();
#else// use this to turn LEDs off during sleepHalLedEnterSleep();
#endif // HAL_SLEEP_DEBUG_LED// enable sleep timer interruptif (timeout != 0){// check if the time to next wake event is greater than max sleep timeif (timeout > MAX_SLEEP_TIME ){// it is, so limit to max allowed sleep time (~510s)halSleepSetTimer( sleepTimer, MAX_SLEEP_TIME );}else // not more than allowed sleep time{// so set sleep time to actual amounthalSleepSetTimer( sleepTimer, timeout );}}// prep CC254x power modeHAL_SLEEP_PREP_POWER_MODE(halPwrMgtMode);// save interrupt enable registers and disable all interruptsHAL_SLEEP_IE_BACKUP_AND_DISABLE(ien0, ien1, ien2);HAL_ENABLE_INTERRUPTS();// set CC254x power mode; interrupts are disabled after this function// Note: Any ISR that could wake the device from sleep needs to use//       CLEAR_SLEEP_MODE(), which will clear the halSleepPconValue flag//       used to enter sleep mode, thereby preventing the device from//       missing this interrupt.HAL_SLEEP_SET_POWER_MODE();// check if ST interrupt pending, and if not, clear wakeForRF flag// Note: This is needed in case we are not woken by the sleep timer but//       by for example a key press. In this case, the flag has to be//       cleared as we are not just before a radio event.// Note: There is the possiblity that we may wake from an interrupt just//       before the sleep timer would have woken us just before a radio//       event, in which case power will be wasted as we will probably//       enter this routine one or more times before the radio event.//       However, this is presumably unusual, and isn't expected to have//       much impact on average power consumption.if ( (wakeForRF == TRUE) && !(IRCON & 0x80) ){wakeForRF = FALSE;}// restore interrupt enable registersHAL_SLEEP_IE_RESTORE(ien0, ien1, ien2);// power on the LL; blocks until completion// Note: This is done here to ensure the 32MHz XOSC has stablized, in//       case it is needed (e.g. the ADC is used by the joystick).LL_PowerOnReq( (halPwrMgtMode == CC2540_PM3), wakeForRF );#ifdef HAL_SLEEP_DEBUG_LEDHAL_TURN_ON_LED3();
#else //!HAL_SLEEP_DEBUG_LED// use this to turn LEDs back on after sleepHalLedExitSleep();
#endif // HAL_SLEEP_DEBUG_LED#if ((defined HAL_KEY) && (HAL_KEY == TRUE))// handle peripherals(void)HalKeyExitSleep();
#endif // ((defined HAL_KEY) && (HAL_KEY == TRUE))}HAL_ENABLE_INTERRUPTS();}

从上面的代码认真分析,就可以掌握BLE的休眠机制。BLE的所有事件都是间断的,而每个事件间的间歇就是定时休眠的时候。例如,广播可以是每个100ms广播一次,而这100ms就进入了PM2休眠的时间;连接的时候,传输数据是10ms或者100ms连接一次传输,数据的传输也是间断的,这个间歇也是PM2的定时休眠时间。BLE正是因为这种休眠机制而做到了很低的功耗,与传统蓝牙的连续传输相比,功耗降低了许多。

以上粗略地总结了TI源码下PM3深度休眠的条件和简单讲述了BLE的休眠机制,本人菜鸟,此文可能存在错误的理解,斗胆发此文,权当和大家交流学习经验,望吐槽。。。

CC2540/CC2541进入PM3深度休眠的条件及其休眠机制的剖析相关推荐

  1. CC2540/CC2541/CC254x之OSAL操作系统抽象层

    测试环境 协议栈版本:BLE-CC254x-1.4.0 开发环境IAR版本:IAR 8.20 硬件设备:CC2540/CC2541开发板 示例测试Demo工程:simpleBLEPeripheral工 ...

  2. CC2540/CC2541的基本操作

    CC2540/CC2541的基本操作 1)操作LED //初始化 P0SEL &= ~0x01;//设置为普通IO口 P0DIR |= 0x01;//设置成输出模式 //LED控制 P0_0 ...

  3. 蓝牙4.0BLE 手机控制 cc2540 CC2541 的串口透传功能已实现

    蓝牙4.0BLE 手机控制 cc2540 CC2541 的串口透传功能已实现 虽然蓝牙4.0 BLE芯片CC2540 是单芯片(即用户可以对它进行芯片级代码编写), 是8051增强型主控, 带蓝牙4. ...

  4. cc2540 cc2541 开发板资料更新日志

    经过多次PCB打样和全面调试.已经完毕了cc2540 cc2541的开发板的批量贴片.硬件告一段落, 接下来是全面完好软件方面的工作.眼下已经针对没有开发经验的用户编写完毕0基础基础实验代码和教程.接 ...

  5. 图文深度解析Linux内存碎片整理实现机制以及源码

    图文深度解析Linux内存碎片整理实现机制以及源码. 物理内存是以页为单位进行管理的,每个内存页大小默认是4K(大页除外).申请物理内存时,一般都是按顺序分配的,但释放内存的行为是随机的.随着系统运行 ...

  6. 易基因|深度综述:表观遗传机制在慢性疼痛中的作用(DNA甲基化+组蛋白修饰+非编码RNA)

    大家好,这里是专注表观组学十余年,领跑多组学科研服务的易基因. 2022年8月22日,德国海德堡大学Daniela Mauceri在<Cells>杂志发表了"Role of Ep ...

  7. 深度学习框架的内存优化机制

    深度学习框架的内存优化机制 https://www.cnblogs.com/DicksonJYL/p/9576896.html 这篇博文简单介绍下深度学习框架的内存优化方式,主要参考资料1,也就是MX ...

  8. 计算机休眠是意思,电脑休眠是什么意思(电脑休眠和睡眠的区别)

    电脑如果长时间不操作的话,就会进入休眠或者睡眠状态,睡眠的话通常晃动鼠标或者键盘就可以唤醒了,而休眠尝尝需要点按一下开机键,那么休眠和睡眠有什么区别呢? windows系统中,有这样几种电源模式,关机 ...

  9. 【李宏毅机器学习2021】Task04 深度学习介绍和反向传播机制

    [李宏毅机器学习2021]本系列是针对datawhale<李宏毅机器学习-2022 10月>的学习笔记.本次是对深度学习介绍和反向传播机制的学习总结.本节针对上节课内容,对batch.梯度 ...

最新文章

  1. 【翻译】SQL Server索引进阶:第七级,过滤的索引
  2. jquery一个控件绑定多个事件
  3. CF176E Archaeology(set用法提示)
  4. android键盘移动光标,在Android键盘上完成键
  5. MyBatis复习(十):注解开发
  6. 对996最客观的描述,一叶知秋
  7. html登录页面的校验控件,HTML5一款有趣智能的密码输入界面控件
  8. c语言中反余切三角函数,三角函数(反双曲)正弦,余弦,正切,余切,正割,余割在线计算器_三贝计算网_23bei.com...
  9. PADS(4)——PADS Logic原理图设计技巧
  10. 新闻APP受到各界关注 趣头条 大众看点 等新闻
  11. 360修复服务器漏洞,360安全漏洞不需要修复怎么设置
  12. 服务交付服务规范十要素
  13. c语言 函数参数传递 值传递,c语言中函数参数的三种传递方式——值传递、指针传递、引用传递...
  14. xx公司网站建设方案
  15. 经典俄罗斯方块游戏使用手册
  16. 流感传染(C程序设计进阶第2周)
  17. 公园智慧路灯:上海曹杨公园智慧灯杆项目案例分享
  18. NEU健康上报脚本解析教程
  19. word论文排版插件_用这个Word插件,瞬间完成一键排版
  20. 男性找女朋友最低会要求什么学历?

热门文章

  1. TX2手动安装cudnn
  2. 帮我用python做三国杀
  3. c# mysql executescalar为什么返回值是空_当没有结果返回时处理ExecuteScalar()
  4. 3D竖版射击游戏Icarus-X
  5. MySQL 复制(四:复制原理)
  6. ROOT学习——跟随鼠标位置动态显示TH2切片(DynamicSlice.C)
  7. 2022年全球市场光学透明胶片总体规模、主要生产商、主要地区、产品和应用细分研究报告
  8. Mask_Rcnn_tf2在2080显卡上训练遇见的问题
  9. 强推!《PyTorch中文手册》来了
  10. C++ 一些http操作函数