参考转自 https://www.sekorm.com/news/9339.html
EFR32MG本身具有五种低功耗工作模式:
EM0:Active状态,此时CPU活动、外设活动,功耗最高,最低65uA/MHz。
EM1:IDLE状态,此时,CPU停止,外设活动,功耗和所使用的外设有关,一般可以认为此时3mA~5mA左右的功耗。
EM2:Deepsleep状态,此时,部分LFXO或LFRCO、ULFRCO低速时钟的外设活动,RAM保存,标称此时电流为1.5uA。
EM3:Stop状态,此时高速时钟HFXO或HFRCO、LFRCO、LFXO均会被关掉,ULFRCO活动,采用ULFRCO的外设仍然可以运行,可选的RAM保存,如RTCC/WDOG/CROTIMER。
EM4H:冬眠状态,从该状态开始,RAM的保存将受到限制,最多通过RTCC外设的RAM区保存128字节的RAM数据。因此,该状态唤醒将会将系统复位。在该状态下,可以使用Cryotimer和指定的GPIO唤醒。
EM4S:关闭状态,在该状态下,所有外设基本都关掉,RAM全部丢失,可以通过基于ULFRCO的Cryotimer或指定的GPIO唤醒,唤醒后系统复位。
在EmberZNet协议栈中,使用到了EM0 、EM1、EM2和EM4H模式,主要的休眠工作在idle-sleep-soc.c line21的void emberAfPluginIdleSleepTickCallback(void)函数中处理。
流程如下:
1.要关闭全局中断,保证睡眠的处理不被中断打断和篡改。
2.是否可以进入休眠,判断条件是
1)开发者是否指定保持唤醒状态不休眠。
2)开发者是否指定未加入网络时不休眠。
3)是否有串口正在发送数据,此时不能休眠。
4)是够有任务等待执行,如果有则不能休眠,要处理就绪的任务,包括用户任务和协议栈任务。
如果这些均全部通过,那至少可以进入IDLE状态了。
3.如果判定可以休眠,对于Sleepy End Device来说,由于RADIO在休眠时是不可以打开的,因此,还需要进行进一步判断是否可以关闭Radio,进入休憩模式,判断依据是查询是否有高优先级的协议栈任务需要运行,目前定义是4个任务具有高优先级:
1)RADIO数据发送任务。
2)RADIO数据接收任务。
3)RADIO外设正在使用。
4)RF4CE网络忙。(一种Zigbee遥控标准协议)
如果有以上任务正在执行,则系统还是不能休眠。
4.如果没有stack高优先级任务在执行,系统就可以安心休眠,首先,需要计算休眠的时间,休眠时间指从现在开始到执行下一个事件发生的时间,以[1/1024]秒为单位,如果计算出来可以休眠的时间小于5ms(系统默认,可修改),那也不可以进入Deepsleep状态,因为进入Deepsleep需要关外设、关协议栈,唤醒后需要开外设、开协议栈,这些动作完成也需要几毫秒的时间,功耗核算下来进入Deepsleep没有任何意义。这种情况下系统会默认进入个EM1 IDLE状态就可以了。如果休眠时间大于5ms,那系统就着手进入deepsleep。再次唤醒时,会给出已经睡眠了多久,用以做调试使用。
注意一点是,无论系统进入IDLE或Deepsleep状态,都会在睡眠之前把中断全部再重新打开,用作唤醒源,但操作是封装在睡眠函数中未开源,我们不要再去手动添加。
接下来,如果我们想要使用EM4--系统最低功耗的模式,那我们需要再进行一点复杂的处理。
首先,EM4唤醒就会复位,因此,在进入EM4之前,要保存Parent Info,也就是父节点的IEEE地址和NodeID,这个不要我们去做,系统会自动添加,在判定是否进入EM4时,默认会进行bool emberParentTokenSet(void)判断是否该操作已经完成,如果未完成则不能进入EM4。同时,需要用户在bool emberAfOKToGoToEM4Callback()函数中返回true,系统才可以确认进入EM4,在进入EM4之前,系统会使用RTCC保存16字节的与当前网络通信加密有关的数据,包括发送数据的FrameCounter、接收数据的FrameCounter、发送数据的LinkKeyFrameCounter、接收数据的LinkKeyFrameCounter,再次唤醒时会自动读取。从EM4唤醒后,系统会获取复位原因,如果是EM4造成的,则会进入void emberAfCameBackFromEM4Callback()函数中,进行EM4的参数回读工作。
但是,使用EM4还是需要做很多工作,因为如果直接使用EM4,会造成周期性的任务事件没有办法执行,每次进入EM4会丢失之前的任务信息,比如Sleepy End Device的Short poll、Long Poll事件无法正常执行。建议是在进入EM4之前就先做好此类工作,bool emberAfOKToGoToEM4Callback()是非常适合的接口。
EM4目前进入机制中协议栈有些地方需要修改,除在ISC文件中选择EM4 plugin外。需要增加EMBER_AF_PLUGIN_EM4、EMBER_ENABLE_EM4定义,重复的定义问题可以去掉$Prj_name.h中的相同定义。在micro.c文件line380 void setEm4WakeupTimer(uint32_t duration)中的 cryotimerInit.period = closestPowerOfTwo(duration);计算周期不正确,请参考手册配置。另外,在child.h文件line 334
#define emberOkToGoToLowPowerMode() (!emberCurrentStackTasks() && emberParentTokenSet())
修改为
#define emberOkToGoToLowPowerMode() (!emberCurrentStackTasks() && !emberParentTokenSet())
原文地址:https://www.cnblogs.com/Daomy/p/9735441.html