SLEEP(休眠控制)

# 功耗管理 ## 简介 Air722UG支持多种省电模式,通过进入不同的省电模式达到降低功耗的目的。 LuatOS-Air版本默认自动休眠控制,系统空闲会自动进入休眠。但是要进行串口,SPI,ADC,I2C操作时,需要调用pm.wake()主动唤醒。操作结束后,需要调用pm.sleep()重新进入自动休眠控制。 注意: 模块是否有进入睡眠模式,从外部电气信号或调试日志中无法体现,只能通过检测模块的消耗电流来判断。进入休眠后模块的电流会在1到2mA的底电流的基础上跳动。 ## 模块功耗指标 - [722u功耗](https://doc.openluat.com/wiki/21?wiki_page_id=2438) ## API说明 |API接口| 描述| | --- | --- | |pm.wake(tag)|某个Lua应用唤醒系统| |pm.sleep(tag)|某个Lua应用休眠系统| |pm.isSleep(tag)|获取系统系统全局或某个Lua应用的休眠状态| |net.switchFly(mode)|设置飞行模式| > 详细的API介绍见[pm API章节](https://doc.openluat.com/wiki/21?wiki_page_id=2287) ## 3种工作模式: ### 1. 全功能模式 一般的工作模式,CPU,时钟全速运行。 ### 2. 休眠模式 CPU休眠,射频部分工作,周期进行寻呼,仅维持网络连接,能随时接收网络端的电话,短信等。功耗较低(具体功耗数据参考6.5章节),主要的省电模式。可以通过GPIO中断,内部计时器中断,网络消息,来电,短信等唤醒。 ### 3. 最少功能模式 RF和SIM都关闭):CPU休眠,射频与SIM卡关闭,无法注册网络,无法接收网络端的任何信息。功耗最低 ## 实现流程 目前的休眠处理有两种方式, 第一种是底层core内部,自动处理,例如tcp发送或者接收数据时,会自动唤醒,发送接收结束后,会自动休眠;这部分不用lua脚本控制、 第二种是lua脚本使用pm.sleep和pm.wake自行控制,例如,uart连接外围设备,uart接收数据前,要主动去pm.wake,这样才能保证前面接收的数据不出错,当不需要通信时,调用pm.sleep;如果有lcd的项目,也是同样道理 #### 全功能模式 - 模块启动后,如果网络端没有数据的接受或者发送,会自动休眠,在脚本中调用pm.wake(tag)使系统保持唤醒,不进入休眠,则是全功能模式 #### 休眠模式 当模块开机后,网络没有进行数据发送、接收数据时,模块会自动进入休眠,下面的举例是使用lua脚本来控制休眠与唤醒 - 使用pm.wake(tag)与pm.sleep(tag)来实现管理 - 唤醒 - 使用pm.wake(tag)来唤醒系统 - 休眠 - 使用pm.sleep(tag)来休眠系统 - 休眠唤醒功能(pm)的原理可以按照如下方式理解 ``` 有一个屋子,屋子里有个电灯,电灯是由电池来供电的,充一次电比较麻烦,所以为了省电,只有当有人需要用 到电灯时,才去打开它。 晚上,屋子里进了一个人,说我要打开灯,于是灯亮了,后面接着进来了三个人,都说自己要打开灯。 等了一会,他们中有一个人要走了,说:我要关掉灯,然后走了,但是这时候屋子里还有其他三个人需要用灯, 所以灯实际上并不会关掉,只有当屋子里所有的人都说要关掉灯,没人用到灯的时候,灯才会关掉。 ``` - 假设模块有两个应用 - 第一个是使用SPI接了LCD屏,应用标记为"LCD" 第二个是使用串口来传输数据,应用标记为"UART" - UART传输数据前需要让系统保持唤醒,使用pm.wake("UART")来使系统保持唤醒状态 同时LCD屏需要显示数据,使用pm.wake("LCD")来保持系统唤醒 - 当UART工作完毕后,使用pm.sleep("UART")来标记串口传输工作已经完毕,但此时LCD还处于工作状态,所以系统无法进行休眠。当LCD应用工作完毕调用pm.sleep("LCD")后,此时"UART"和"LCD"都工作完毕了,系统才会真正进入休眠 - 更多应用同理 - 假设模块有一个应用 - 使用串口来传输数据,应用标记为"UART" - UART传输数据前需要让系统保持唤醒,使用pm.wake(“UART”)来使系统保持唤醒状态,当UART工作完毕后,使用pm.sleep(“UART”)来标记串口传输工作已经完毕,此时没有其他应用唤醒模块,系统可以真正地进行休眠 #### 最少功能模式 系统休眠,并且模块进入飞行模式 - 有两种实现的方法 - 第一种:开机10秒后或开机20秒模块注册上网络后调用 net.switchFly(true)使模块进入飞行模式,等待系统自动休眠后,进入最少功能模式 - 第二种:待模块任务执行完毕,但不想让它关机时,调用 pm.sleep(tag)与net.switchFly(true)使模块进入休眠并进入飞行模式 ## 示例 [这里是功耗管理demo的章节,请点我](http://doc.openluat.com/wiki/21?wiki_page_id=2187) ### 全功能模式 ```lua sys.taskInit( function() sys.wait(5000) --挂起五秒,等待模块开机 pm.wake("WAKE") --模块开机后调用pm.wake(tag)(这里"WAKE"为tag),使系统保持唤醒状态 end ) ``` ### 休眠模式 ```lua sys.taskInit( function() --等待十秒,十秒后,保持系统唤醒 sys.wait(8000) --两秒后打印当前"TEST"和全局脚本的休眠状态,true为休眠状态,false为唤醒状态 sys.wait(2000) print("执行pm.wake(\"TEST\")之前\"TEST\"的休眠状态:",pm.isSleep("TEST"),"全局的休眠状态:",pm.isSleep()) pm.wake("TEST") --两秒后打印当前"TEST"和全局脚本的休眠状态,true为休眠状态,false为唤醒状态 sys.wait(2000) print("执行pm.wake(\"TEST\")后\"TEST\"的休眠状态:",pm.isSleep("TEST"),"全局的休眠状态:",pm.isSleep()) local temp = 0 --循环打印二十次,等待20秒后,进入休眠 while temp < 20 do print("我现在正在执行打印任务") sys.wait(1000) temp = temp + 1 end print("我休眠了") --调用接口使模块休眠 pm.sleep("TEST") sys.wait(2000) print("执行pm.sleep(\"TEST\")后\"TEST\"的休眠状态:",pm.isSleep("TEST"),"全局的休眠状态:",pm.isSleep()) end ) ``` ### 最少功能模式 ```lua sys.taskInit( function() --等待10秒 --刚开机就进入飞行模式可能会失败,所以开机后等待10s或注册上网络后再进入飞行模式 sys.wait(10000) --进入飞行模式 net.switchFly(true) --等待两秒 sys.wait(2000) print("我休眠了") --调用接口使模块休眠 pm.sleep("TEST") end ) ``` ## 常见问题 **一、飞行模式 和 超低功耗模式 哪个更省电?** 飞行低,但退出飞行模式重新联网需要时间,飞行模式下,没法维持模块与服务器连接,根据实际业务情况选。 如果开关飞行频率过大,功耗也会增加。 **二、为什么模块无法进入休眠** 1. 查看模块是否插入USB,USB连接的状态(usb_VBUS,usb_DP,usb_DM电压都正常)下模块保持唤醒,无法休眠 2. 使用开发板和自己的板子烧录adc的demo进行对比,看模块是否能够进行休眠 3. 使用pm.isSleep()接口查询脚本休眠状态,看是否是调用了pm.wake(tag)后没有去调用pm.sleep(tag) 4. 屏蔽代码,看是由哪部分代码使模块无法休眠 5. 定时器的频率会影响到休眠功耗, 例如: sys.wait(10)和sys.wait(100); sys.timerStart(function() log.info("TEST") end,10) 和 sys.timerStart(function() log.info("TEST") end,100) 6. pwm功能开启状态下模块无法进入休眠 例如: 在脚本内加入开启pwm功能的代码后,模块无法进入休眠 misc.openPwm(0,512,496) 开启pwm后需要调用misc.closePwm(0)来关闭pwm功能,模块才可以进入休眠 7. 模块外围有连接MCU,如何通过模块的io口控制模块的休眠与唤醒? 举例:将模块的一个io设置为中断,MCU与模块io相连,拉高时使模块唤醒,拉低时使模 块进入休眠 如: ```lua function gpioInt_9(msg) --GPIO_9的中断处理函数 if msg == cpu.INT_GPIO_POSEDGE then --高电平中断时唤醒 log.warn("使用了pm.wake()来使系统唤醒") pm.wake("TEST") else --低电平中断时休眠 log.warn("使用了pm.slepp()来使系统休眠") pm.sleep("TEST") end end pin9 = pins.setup(pio.P0_9, gpioInt_9) ``` **三、为什么串口1在休眠状态下也能正常收发数据** uart1在core中做了特殊处理,可以实现休眠状态下接收数据不丢失 **四、模块支持PSM省电模式吗?** cat.1模块目前不支持这个模式,PSM应该是展锐1.4基线上新增的功能,模块目前还是1.3基线,后续我们有可能会移植,时期不确定 UE Power Saving Mode(简称PSM)是3GPP R12引入的特性,面向小数据量传输场景功耗体验优化与信令开销控制。 在PSM模式下,网络无法到达UE,UE无需接受来自于网络的数据和请求(以获得类似于关机的功耗表现),但是依然注册在网络,NAS(非接入层)的状态信息得以保留,AS(接入层)连接已经关闭,这样UE在退出PSM模式的时候,只需重新建立RRC连接,无需重新做Attach或者PDN连接,从而实现接入信令开销的控制。 **五、为什么模块在进行网络数据收发的时候,收发的数据很短,但很长时间功耗才会降下来?** UE没有网络数据交互的时候是处于空闲态(UE:用户设备,这里指我们的模块) 当有数据收发时,UE会向基站请求连接 UE与基站建立链接后由空闲态转为链接态,处于链接态的UE功耗是比较高的。 收发数据是很短时间内的事情 之所以会有一段时间的高功耗:是因为模块收发完一次网络数据后,会等待一段时间 这段时间专业术语叫做UeInactive timer(UE不活动定时器) 在定时器超时前,UE与基站不会断开链接,有网络数据收发时,不用再与基站重新建立链接 当定时器超时后,UE与基站会断开链接,由链接态转为空闲态,功耗自然就降下来了。 这个时间可以通过AT*RTIME=< n >设置,详细说明见:[长连接超低功耗方案](https://doc.openluat.com/wiki/21?wiki_page_id=1969 "长连接超低功耗方案")