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 "长连接超低功耗方案")