(Z-STACK) Zigbee电源管理

2019-07-13 23:48发布

要使用电源管理,需要预编译POWER_SAVING. 预备知识: #define PWRMGR_ALWAYS_ON  0   //协调器或者路由器不能休眠
#define PWRMGR_BATTERY    1     //终端可以休眠
  #define PWRMGR_CONSERVE 0 //PWRMGR_CONSERVE任务处于省电状态
#define PWRMGR_HOLD     1  //PWRMGR_HOLD任务处于工作状态
  typedef struct
{
  uint16 pwrmgr_task_state;            //任务的电源管理状态,允许为bit0,不允许为bit1
  uint16 pwrmgr_next_timeout;       //下一次超时时间
  uint16 accumulated_sleep_time;
  uint8  pwrmgr_device;                  //电源管理设备属性,PWRMGR_ALWAYS_ON  PWRMGR_BATTERY对应
} pwrmgr_attribute_t;//电源管理结构体
定义了pwrmgr_attribute_t    pwrmgr_attribute; 1.osal_pwrmgr_init()//初始化电源管理系统,默认为PWRMGR_ALWAYS_ON  和pwrmgr_task_state=0(所有任务支持电源管理); 2.osal_pwrmgr_device(uint8 )//设置电源管理设备属性。为PWRMGR_ALWAYS_ON  或者PWRMGR_BATTERY 3.osal_pwrmgr_task_state(uint8 task_id, uint8 state)//state为PWRMGR_CONSERVE或者PWRMGR_HOLD,设置任务允不允许电源管理。 4.osal_pwrmgr_powerconserve()//判断是否所有的任务都允许电源管理,查找出最低timeout的timeer返回timeout,timer表为空返回0,最后调用halSleep,进入休眠状态。     1在【Zmain.c中】osal_start_system()-------->osal_pwrmgr_powerconserve() 2可以使用osal_pwrmgr_task_state( uint8 task_id, uint8 state )来使某个任务支持或不支持电源管理 3在ZDApp_event_loop()中           osal_pwrmgr_device( PWRMGR_ALWAYS_ON );//路由器不能使用电源管理   在ZDApp_NetworkStartEvt()中          osal_pwrmgr_device( PWRMGR_ALWAYS_ON );//协调器一直有电  在ZDApp_DeviceAuthEvt()中          #if defined ( POWER_SAVING )
        osal_pwrmgr_device( PWRMGR_BATTERY );//end可以选择性的电源管理
        #endif
在ZDApp_ProcessNetworkJoin()中ZDApp_ProcessNetworkJoin()中        #if defined ( POWER_SAVING )
         osal_pwrmgr_device( PWRMGR_BATTERY );
      #endif
   CC2530有3种睡眠模式: #define CC2530_PM0            0  /* PM0, Clock oscillators on, voltage regulator on */ #define CC2530_PM1            1  /* PM1, 32.768 kHz oscillators on, voltage regulator on */
#define CC2530_PM2            2  /* PM2, 32.768 kHz oscillators on, voltage regulator off */
#define CC2530_PM3            3  /* PM3, All clock oscillators off, voltage regulator off */

  #define HAL_SLEEP_OFF         CC2530_PM0  //
#define HAL_SLEEP_TIMER       CC2530_PM2//可通过定时器和外部中断或者复位唤醒
#define HAL_SLEEP_DEEP        CC2530_PM3//外部中断或者复位唤醒
pm2模式比较省功耗而且可以被定时唤醒;pm3模式最省电但是只能被外部中断唤醒
  要设置低功耗模式,先确认: 1.f8wConfig.cfg文件中DRFD_RCVC_ALWAYS_ON定义为FALSE 2.Options->C/C++Compiler->Defined symbols中添加预编译“POWER_SAVING”;
在Options->Linker->Linker command line里面把f8w2430.xcl改为f8w2430pm.xcl。
重要函数void halSleep( uint16 osal_timeout ) 1.首先将osal_timeout转成以320US为单位 2.获取下一次MAC定时器到期时间 3.  halPwrMgtMode = (timeout == 0) ? HAL_SLEEP_DEEP : HAL_SLEEP_TIMER;   //为PM2,PM3模式。 没有任务要执行就进入PM3深度睡眠,否则进入PM2睡眠,可以定时器唤醒。 4.唤醒

Power Modes Active mode: The fully functional mode. The voltage regulator to the digital core is on, and either the 16-MHz RC oscillator or the 32-MHz crystal oscillator or both are running. Either the 32-kHz RCOSC or the 32-kHz XOSC is running. Idle mode: Identical to active mode, except that the CPU core stops operating (is idle). PM1: The voltage regulator to the digital part is on. Neither the 32-MHz XOSC nor the 16-MHz RCOSC is running. Either the 32-kHz RCOSC or the 32-kHz XOSC is running. The system goes to active mode on reset, an external interrupt, or when the Sleep Timer expires. PM2: The voltage regulator to the digital core is turned off. Neither the 32-MHz XOSC nor the 16-MHz RCOSC is running. Either the 32-kHz RCOSC or the 32-kHz XOSC is running. The system goes to active mode on reset, an external interrupt, or when the Sleep Timer expires. PM3: The voltage regulator to the digital core is turned off. None of the oscillators is running. The system goes to active mode on reset or an external interrupt.The POR is active in PM2/PM3, but the BOD is powered down, which gives a limited voltage supervision. If the supply voltage is lowered to below 1.4 V during PM2/PM3, at temperatures of 70°C or higher, and then brought back up to good operating voltage before active mode is re-entered, registers and RAM contents that are saved in PM2/PM3 may become altered. Hence, care should be taken in the design of the system power supply to ensure that this does not occur. The voltage can be periodically supervised accurately by entering active mode, as a BOD reset is triggered if the supply voltage is below approximately 1.7 V. The CC2533 and CC2541 have functionality to perform automatically a CRC check of the retained configuration register values in PM2/PM3 to check that the device state was not altered during sleep. The bits in SRCRC.CRC_RESULT indicate whether there were any changes, and by enabling SRCRC.CRC_RESET_EN, the device immediately resets itself with a watchdog reset if SRCRC.CRC_RESULT is not 00 (= CRC of retained registers passed) after wakeup from PM2/PM3. The SRCRC register also contains the SRCRC.FORCE_RESET bit that can be used by software to immediately trigger a watchdog reset to reboot the device. 必须满足下面所有条件才能进入休眠模式 1. ZDO节点描述符指定“Rx is off when idle,在f8wConfig.cfg文件中将RFD_RCVC_ALWAYS_ON设为false实现 2. 所有zstack 任务”赞同“进入睡眠模式 3. zstack各个任务都没有预定的活动 4.MAC层没有预定的活动 cc2531和cc2530 zigbee协议栈工程中调用以下函数使设备进入低功耗状态。在这里(osal_pwrmgr_powerconserve()函数中),在尝试进入休眠模式时会做另外两个检查。首先,检查变量pwrmgr_device是否被设置为电池设备。这项设定在设备入网后执行—详情见例程的ZDApp.c源文件。其次,检查变量pwrmgr_task_state确认没有任务的节能状态是“put a hold”。该机制允许每个Z-Stack任务在临界区操作时禁止休眠。当这两个条件都满足时,预期的休眠时间取决于OSAL定时器的下一次溢出时间。如果下一次溢出时间大于0小于MIN_SLEEP_TIME,选择SLEEP_LITE模式。在这种模式下,系统定时器被调整为首先到期的定时器事件提供一个“唤醒”中断。MIN_SLEEP_TIME定义在hal_sleep.c中,为了防止很短时间的休眠。当没有预定的Z-Stack 事件或者定时器时,选择SLEEP_DEEP模式,因此下一次溢出时间为0,允许最大限度的节能: void osal_pwrmgr_powerconserve( void ) {   uint16        next;   halIntState_t intState;     // Should we even look into power conservation   if ( pwrmgr_attribute.pwrmgr_device != PWRMGR_ALWAYS_ON )   {     // Are all tasks in agreement to conserve     if ( pwrmgr_attribute.pwrmgr_task_state == 0 )     {       // Hold off interrupts.       HAL_ENTER_CRITICAL_SECTION( intState );         // Get next time-out       next = osal_next_timeout();         // Re-enable interrupts.       HAL_EXIT_CRITICAL_SECTION( intState );         // Put the processor into sleep mode       OSAL_SET_CPU_INTO_SLEEP( next );     }   } }   以上函数实际调用的是halSleep(),该函数通过对休眠时间,设定条件和堆栈分配情况的判断来选择节点进入PM1,PM2,PM3。halSleep()函数被OSAL_SET_CPU_INTO_SLEEP调用,该函数执行一系列有序的操作:关闭MAC层,关断外设,使MCU进入休眠模式,休眠后唤醒MCU,开启外设,最后重启MAC层。Z-Stack OSAL主循环独立运行于MAC层,因此Z-Stack不知道MAC层的运行状态。调用MAC_PwrOffReq()函数可以关闭MAC层。需要注意的是,当设置空闲时接收器使能会导致MAC层休眠时不关闭,这会阻止设备进入休眠模式   /**************************************************************************************************  * @fn          halSleep  *  * @brief       This function is called from the OSAL task loop using and existing OSAL  *              interface.  It sets the low power mode of the MAC and the CC2530.  *  * input parameters  *  * @param       osal_timeout - Next OSAL timer timeout.  *  * output parameters  *  * None.  *  * @return      None.  **************************************************************************************************  */ void halSleep( uint16 osal_timeout ) {   uint32        timeout;   uint32        macTimeout = 0;     /* get next OSAL timer expiration converted to 320 usec units */   timeout = HAL_SLEEP_MS_TO_320US(osal_timeout); 。 。 涉及文件 OSAL_PwrMgr.h OSAL电源管理的API头文件 OSAL_PwrMgr.C OSAL电源管理的API C文件 hal_sleep.c 底层的电源管理文件 电源管理结构体 typedef struct { uint16 pwrmgr_task_state; //任务状态 uint16 pwrmgr_next_timeout; //下一次超时 uint16 accumulated_sleep_time; //睡眠时间 uint8 pwrmgr_device; //电源管理设备属性,有PWRMGR_ALWAYS_ON和 //PWRMGR_BATTERY两种 } pwrmgr_attribute_t; #define PWRMGR_ALWAYS_ON 0 #define PWRMGR_BATTERY 1 选择PWRMGR_ALWAYS_ON的话将不会进入睡眠模式,选择PWRMGR_BATTERY将允许HAL管理CPU进入SLEEP LITE或者SLEEP DEEP状态。 #define PWRMGR_CONSERVE 0 #define PWRMGR_HOLD 1 低功耗标志,主要用于osal_pwrmgr_task_state()这个函数中,用于标志每一任务是否需要低功耗。 extern pwrmgr_attribute_t pwrmgr_attribute; 定义一个电源管理的全局变量。 函数 void osal_pwrmgr_init( void ) { pwrmgr_attribute.pwrmgr_device = PWRMGR_ALWAYS_ON; //默认没有睡眠模式 pwrmgr_attribute.pwrmgr_task_state = 0; //清零 } uint8 osal_pwrmgr_task_state( uint8 task_id, uint8 state ) { if ( task_id >= tasksCnt ) return ( INVALID_TASK ); if ( state == PWRMGR_CONSERVE ) { // 清零 pwrmgr_attribute.pwrmgr_task_state &= ~(1 << task_id ); } else { //置位 pwrmgr_attribute.pwrmgr_task_state |= (1 << task_id); } return ( SUCCESS ); } #if defined( POWER_SAVING ) void osal_pwrmgr_powerconserve( void ) { uint16 next; halIntState_t intState; // 首先检查是否支持低功耗 if ( pwrmgr_attribute.pwrmgr_device != PWRMGR_ALWAYS_ON ) { //是否所有任务支持低功耗 if ( pwrmgr_attribute.pwrmgr_task_state == 0 ) { //关中断 HAL_ENTER_CRITICAL_SECTION( intState ); //查询软件定时器链表得到最近一次溢出时间 next = osal_next_timeout(); //开中断 HAL_EXIT_CRITICAL_SECTION( intState ); //将系统进入睡眠模式 OSAL_SET_CPU_INTO_SLEEP( next ); } } } #endif 加红部分是一个宏定义,在OnBoard.h里面定义的。 #define OSAL_SET_CPU_INTO_SLEEP(timeout) halSleep(timeout); halSleep(timeout)是在hal_sleep.c中定义的。 这里面涉及的就是关于CC2530的电源管理寄存器的一些操作。具体可以看代码。 #define HAL_SLEEP_OFF CC2530_PM0 #define HAL_SLEEP_TIMER CC2530_PM2 #define HAL_SLEEP_DEEP CC2530_PM3 #define CC2530_PM0 0 #define CC2530_PM1 1 #define CC2530_PM2 2 #define CC2530_PM3 3 #define MAX_SLEEP_TIME 510000 最大睡眠时间是510000ms。 总结 其实可以在这个函数中可以看到在OSAL中是使用的睡眠定时器来控制睡眠时间的,在系统初始化的是将电源控制结构体中的pwrmgr_device设备属性设置为PWRMGR_ALWAYS_ON,这样默认就不进入休眠状态。必须在应用层里面调用void osal_pwrmgr_device( uint8 pwrmgr_device )这个OSAL的API来设置使得OSAL能够进入休眠状态。 在用户任务中需要用的这样一个API——uint8 osal_pwrmgr_task_state( uint8 task_id, uint8 state )来设置这个任务是否支持休眠,如果有一个任务不支持休眠的话,整个系统就将不会进入休眠模式。这个在void osal_pwrmgr_powerconserve( void )中有相关的查询。 在OSAL的主循环中void osal_start_system( void )调用了osal_pwrmgr_powerconserve这个函数。 void osal_start_system( void ) { #if !defined ( ZBIT ) && !defined ( UBIT ) for(;;) // Forever Loop #endif { uint8 idx = 0; osalTimeUpdate(); Hal_ProcessPoll(); // This replaces MT_SerialPoll() and osal_check_timer(). do { if (tasksEvents[idx]) // Task is highest priority that is ready. { break; } } while (++idx < tasksCnt); if (idx < tasksCnt) { uint16 events; halIntState_t intState; HAL_ENTER_CRITICAL_SECTION(intState); events = tasksEvents[idx]; tasksEvents[idx] = 0; // Clear the Events for this task. HAL_EXIT_CRITICAL_SECTION(intState); events = (tasksArr[idx])( idx, events ); //最关键的一句话,如图一中,运行对应的任务 HAL_ENTER_CRITICAL_SECTION(intState); tasksEvents[idx] |= events; // Add back unprocessed events to the current task. HAL_EXIT_CRITICAL_SECTION(intState); } #if defined( POWER_SAVING ) else // Complete pass through all task events with no activity? { osal_pwrmgr_powerconserve(); // Put the processor/system into sleep } #endif } } 表示OSAL系统在检查完所有的任务事件之后发现没有事件需要处理,这样在POWER_SAVING宏定义打开的情况下将调用osal_pwrmgr_powerconserve();函数,在这函数中将会根据选择系统进入休眠。 退出休眠 当出现IO中断或者复位时候会退出休眠,或者在休眠定时器中断时候也将会退出休眠。如果是IO中断或者休眠定时器中断退出之后将回到进入休眠的地方继续向下执行,复位退出的话进入程序的初部分执行。

pm2模式比较省功耗而且可以被定时唤醒;pm3模式最省电但是只能被外部中断唤醒。 开启睡眠功能很简单: 首先确认Texas InstrumentsStack-1.4.3-1.2.1ProjectszstackToolsCC2430DB目录下的 f8wConfig.cfg文件中DRFD_RCVC_ALWAYS_ON定义为FALSE;
然后在IAR的Options->C/C++Compiler->Defined symbols中添加“POWER_SAVING”;
最后在Options->Linker->Linker command line里面把f8w2430.xcl改为f8w2430pm.xcl。 在定义“POWER_SAVING”宏以后OSAL.c中的osal_start_system()函数里面就会调用 osal_pwrmgr_powerconserve()函数。osal_pwrmgr_powerconserve()函数把获取os层timer的下一次的到时时间作为参数,调用hal_sleep()进入pm2睡眠模式,如果当前没有任务那么将进入pm3。所以说一旦启用省电模式,系统将根据当前的任务自动进入睡眠,睡眠前设置sleeptimer,醒来的时间刚好等于下次任务到来的时间,当完成任务后再次进入睡眠。

涉及文件 OSAL_PwrMgr.h OSAL电源管理的API头文件 OSAL_PwrMgr.C OSAL电源管理的API C文件 hal_sleep.c 底层的电源管理文件 电源管理结构体 typedef struct { uint16 pwrmgr_task_state; //任务状态 uint16 pwrmgr_next_timeout; //下一次超时 uint16 accumulated_sleep_time; //睡眠时间 uint8 pwrmgr_device; //电源管理设备属性,有PWRMGR_ALWAYS_ON和 //PWRMGR_BATTERY两种 } pwrmgr_attribute_t; #define PWRMGR_ALWAYS_ON 0 #define PWRMGR_BATTERY 1 选择PWRMGR_ALWAYS_ON的话将不会进入睡眠模式,选择PWRMGR_BATTERY将允许HAL管理CPU进入SLEEP LITE或者SLEEP DEEP状态。 #define PWRMGR_CONSERVE 0 #define PWRMGR_HOLD 1 低功耗标志,主要用于osal_pwrmgr_task_state()这个函数中,用于标志每一任务是否需要低功耗。 extern pwrmgr_attribute_t pwrmgr_attribute; 定义一个电源管理的全局变量。 函数 void osal_pwrmgr_init( void ) { pwrmgr_attribute.pwrmgr_device = PWRMGR_ALWAYS_ON; //默认没有睡眠模式 pwrmgr_attribute.pwrmgr_task_state = 0; //清零 } uint8 osal_pwrmgr_task_state( uint8 task_id, uint8 state ) { if ( task_id >= tasksCnt ) return ( INVALID_TASK ); if ( state == PWRMGR_CONSERVE ) { // 清零 pwrmgr_attribute.pwrmgr_task_state &= ~(1 << task_id ); } else { //置位 pwrmgr_attribute.pwrmgr_task_state |= (1 << task_id); } return ( SUCCESS ); } #if defined( POWER_SAVING ) void osal_pwrmgr_powerconserve( void ) { uint16 next; halIntState_t intState; // 首先检查是否支持低功耗 if ( pwrmgr_attribute.pwrmgr_device != PWRMGR_ALWAYS_ON ) { //是否所有任务支持低功耗 if ( pwrmgr_attribute.pwrmgr_task_state == 0 ) { //关中断 HAL_ENTER_CRITICAL_SECTION( intState ); //查询软件定时器链表得到最近一次溢出时间 next = osal_next_timeout(); //开中断 HAL_EXIT_CRITICAL_SECTION( intState ); //将系统进入睡眠模式 OSAL_SET_CPU_INTO_SLEEP( next ); } } } #endif 加红部分是一个宏定义,在OnBoard.h里面定义的。 #define OSAL_SET_CPU_INTO_SLEEP(timeout) halSleep(timeout); halSleep(timeout)是在hal_sleep.c中定义的。 这里面涉及的就是关于CC2530的电源管理寄存器的一些操作。具体可以看代码。 #define HAL_SLEEP_OFF CC2530_PM0 #define HAL_SLEEP_TIMER CC2530_PM2 #define HAL_SLEEP_DEEP CC2530_PM3 #define CC2530_PM0 0 #define CC2530_PM1 1 #define CC2530_PM2 2 #define CC2530_PM3 3 #define MAX_SLEEP_TIME 510000 最大睡眠时间是510000ms。 总结 其实可以在这个函数中可以看到在OSAL中是使用的睡眠定时器来控制睡眠时间的,在系统初始化的是将电源控制结构体中的pwrmgr_device设备属性设置为PWRMGR_ALWAYS_ON,这样默认就不进入休眠状态。必须在应用层里面调用void osal_pwrmgr_device( uint8 pwrmgr_device )这个OSAL的API来设置使得OSAL能够进入休眠状态。 在用户任务中需要用的这样一个API——uint8 osal_pwrmgr_task_state( uint8 task_id, uint8 state )来设置这个任务是否支持休眠,如果有一个任务不支持休眠的话,整个系统就将不会进入休眠模式。这个在void osal_pwrmgr_powerconserve( void )中有相关的查询。 在OSAL的主循环中void osal_start_system( void )调用了osal_pwrmgr_powerconserve这个函数。 void osal_start_system( void ) { #if !defined ( ZBIT ) && !defined ( UBIT ) for(;;) // Forever Loop #endif { uint8 idx = 0; osalTimeUpdate(); Hal_ProcessPoll(); // This replaces MT_SerialPoll() and osal_check_timer(). do { if (tasksEvents[idx]) // Task is highest priority that is ready. { break; } } while (++idx < tasksCnt); if (idx < tasksCnt) { uint16 events; halIntState_t intState; HAL_ENTER_CRITICAL_SECTION(intState); events = tasksEvents[idx]; tasksEvents[idx] = 0; // Clear the Events for this task. HAL_EXIT_CRITICAL_SECTION(intState); events = (tasksArr[idx])( idx, events ); //最关键的一句话,如图一中,运行对应的任务 HAL_ENTER_CRITICAL_SECTION(intState); tasksEvents[idx] |= events; // Add back unprocessed events to the current task. HAL_EXIT_CRITICAL_SECTION(intState); } #if defined( POWER_SAVING ) else // Complete pass through all task events with no activity? { osal_pwrmgr_powerconserve(); // Put the processor/system into sleep } #endif } } 表示OSAL系统在检查完所有的任务事件之后发现没有事件需要处理,这样在POWER_SAVING宏定义打开的情况下将调用osal_pwrmgr_powerconserve();函数,在这函数中将会根据选择系统进入休眠。 退出休眠 当出现IO中断或者复位时候会退出休眠,或者在休眠定时器中断时候也将会退出休眠。如果是IO中断或者休眠定时器中断退出之后将回到进入休眠的地方继续向下执行,复位退出的话进入程序的初部分执行。


涉及文件 OSAL_PwrMgr.h OSAL电源管理的API头文件 OSAL_PwrMgr.C OSAL电源管理的API C文件 hal_sleep.c 底层的电源管理文件 电源管理结构体 typedef struct { uint16 pwrmgr_task_state; //任务状态 uint16 pwrmgr_next_timeout; //下一次超时 uint16 accumulated_sleep_time; //睡眠时间 uint8 pwrmgr_device; //电源管理设备属性,有PWRMGR_ALWAYS_ON和 //PWRMGR_BATTERY两种 } pwrmgr_attribute_t; #define PWRMGR_ALWAYS_ON 0 #define PWRMGR_BATTERY 1 选择PWRMGR_ALWAYS_ON的话将不会进入睡眠模式,选择PWRMGR_BATTERY将允许HAL管理CPU进入SLEEP LITE或者SLEEP DEEP状态。 #define PWRMGR_CONSERVE 0 #define PWRMGR_HOLD 1 低功耗标志,主要用于osal_pwrmgr_task_state()这个函数中,用于标志每一任务是否需要低功耗。 extern pwrmgr_attribute_t pwrmgr_attribute; 定义一个电源管理的全局变量。 函数 void osal_pwrmgr_init( void ) { pwrmgr_attribute.pwrmgr_device = PWRMGR_ALWAYS_ON; //默认没有睡眠模式 pwrmgr_attribute.pwrmgr_task_state = 0; //清零 } uint8 osal_pwrmgr_task_state( uint8 task_id, uint8 state ) { if ( task_id >= tasksCnt ) return ( INVALID_TASK ); if ( state == PWRMGR_CONSERVE ) { // 清零 pwrmgr_attribute.pwrmgr_task_state &= ~(1 << task_id ); } else { //置位 pwrmgr_attribute.pwrmgr_task_state |= (1 << task_id); } return ( SUCCESS ); } #if defined( POWER_SAVING ) void osal_pwrmgr_powerconserve( void ) { uint16 next; halIntState_t intState; // 首先检查是否支持低功耗 if ( pwrmgr_attribute.pwrmgr_device != PWRMGR_ALWAYS_ON ) { //是否所有任务支持低功耗 if ( pwrmgr_attribute.pwrmgr_task_state == 0 ) { //关中断 HAL_ENTER_CRITICAL_SECTION( intState ); //查询软件定时器链表得到最近一次溢出时间 next = osal_next_timeout(); //开中断 HAL_EXIT_CRITICAL_SECTION( intState ); //将系统进入睡眠模式 OSAL_SET_CPU_INTO_SLEEP( next ); } } } #endif 加红部分是一个宏定义,在OnBoard.h里面定义的。 #define OSAL_SET_CPU_INTO_SLEEP(timeout) halSleep(timeout); halSleep(timeout)是在hal_sleep.c中定义的。 这里面涉及的就是关于CC2530的电源管理寄存器的一些操作。具体可以看代码。 #define HAL_SLEEP_OFF CC2530_PM0 #define HAL_SLEEP_TIMER CC2530_PM2 #define HAL_SLEEP_DEEP CC2530_PM3 #define CC2530_PM0 0 #define CC2530_PM1 1 #define CC2530_PM2 2 #define CC2530_PM3 3 #define MAX_SLEEP_TIME 510000 最大睡眠时间是510000ms。 总结 其实可以在这个函数中可以看到在OSAL中是使用的睡眠定时器来控制睡眠时间的,在系统初始化的是将电源控制结构体中的pwrmgr_device设备属性设置为PWRMGR_ALWAYS_ON,这样默认就不进入休眠状态。必须在应用层里面调用void osal_pwrmgr_device( uint8 pwrmgr_device )这个OSAL的API来设置使得OSAL能够进入休眠状态。 在用户任务中需要用的这样一个API——uint8 osal_pwrmgr_task_state( uint8 task_id, uint8 state )来设置这个任务是否支持休眠,如果有一个任务不支持休眠的话,整个系统就将不会进入休眠模式。这个在void osal_pwrmgr_powerconserve( void )中有相关的查询。 在OSAL的主循环中void osal_start_system( void )调用了osal_pwrmgr_powerconserve这个函数。 void osal_start_system( void ) { #if !defined ( ZBIT ) && !defined ( UBIT ) for(;;) // Forever Loop #endif { uint8 idx = 0; osalTimeUpdate(); Hal_ProcessPoll(); // This replaces MT_SerialPoll() and osal_check_timer(). do { if (tasksEvents[idx]) // Task is highest priority that is ready. { break; } } while (++idx < tasksCnt); if (idx < tasksCnt) { uint16 events; halIntState_t intState; HAL_ENTER_CRITICAL_SECTION(intState); events = tasksEvents[idx]; tasksEvents[idx] = 0; // Clear the Events for this task. HAL_EXIT_CRITICAL_SECTION(intState); events = (tasksArr[idx])( idx, events ); //最关键的一句话,如图一中,运行对应的任务 HAL_ENTER_CRITICAL_SECTION(intState); tasksEvents[idx] |= events; // Add back unprocessed events to the current task. HAL_EXIT_CRITICAL_SECTION(intState); } #if defined( POWER_SAVING ) else // Complete pass through all task events with no activity? { osal_pwrmgr_powerconserve(); // Put the processor/system into sleep } #endif } } 表示OSAL系统在检查完所有的任务事件之后发现没有事件需要处理,这样在POWER_SAVING宏定义打开的情况下将调用osal_pwrmgr_powerconserve();函数,在这函数中将会根据选择系统进入休眠。 退出休眠 当出现IO中断或者复位时候会退出休眠,或者在休眠定时器中断时候也将会退出休眠。如果是IO中断或者休眠定时器中断退出之后将回到进入休眠的地方继续向下执行,复位退出的话进入程序的初部分执行。