BLE 协议栈之低功耗管理

BLE 协议栈中电源低功耗的管理与CC2530的模式一样,都有PM1,PM2,PM3三种低功耗状态,其中PM2在可以用定时器唤醒,在PM3中只能使用外部中断的方式才能唤醒。

下面的程序实现的是在CC2541片子上使用低功耗电源管理芯片TPS62730,控制引脚在P1_0位置。

 

程序运行到osal_start_system();后继而运行到osal_run_system();

在里面有一个  osal_pwrmgr_powerconserve();函数,是系统自动检测当前是否有任务在执行,没哟的话将进入低功耗模式。

void osal_pwrmgr_powerconserve( void )  // 系统自动调用 如果当前没有任务,将进入低功耗模式
{
  uint32        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();   //选取最近事件的Timeout 作为实际休眠时间 
      // Re-enable interrupts.
      HAL_EXIT_CRITICAL_SECTION( intState );
     // Put the processor into sleep mode
      OSAL_SET_CPU_INTO_SLEEP( next );   // 进入低功耗模式   
    }
  }
}

 


进入低功耗模式之后,会执行halsleep()函数进行低功耗模式设置。

里面进行了低功耗时间等设置,进行电源控制的启动就在这里使能!

void  halSleep( uint32 osal_timeout )
{
  uint32 timeout;
  uint32 llTimeout;
  uint32 sleepTimer;

#ifdef DEBUG_GPIO
  // TEMP
  P1_0 = 1;
#endif // DEBUG_GPIO

  // max allowed sleep time in ms
  if (osal_timeout > MAX_SLEEP_TIMEOUT)
  {
    osal_timeout = MAX_SLEEP_TIMEOUT;
  }

  // get LL timeout value already converted to 32kHz ticks
  LL_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 variable
    timeout = 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 value
    if ((llTimeout != 0) && (llTimeout < timeout))
    {
      // use common variable
      timeout = llTimeout;

      // the next ST wake time is due to radio
      wakeForRF = TRUE;
    }
    else // OSAL timeout will be used to wake
    {
      // so take a snapshot of the sleep timer for sleep based on OSAL timeout
      sleepTimer = halSleepReadTimer();

      // the next ST wake time is not due to radio
      wakeForRF = FALSE;
    }
  }

  // HAL_SLEEP_PM3 is entered only if the timeout is zero
  halPwrMgtMode = (timeout == 0) ? HAL_SLEEP_DEEP : HAL_SLEEP_TIMER;  // 选择进入PM 模式

#ifdef DEBUG_GPIO
  // TEMP
  P1_0 = 0;
#endif // DEBUG_GPIO

  // check if sleep should be entered
  if ( (timeout > PM_MIN_SLEEP_TIME) || (timeout == 0) )
  {
    halIntState_t ien0, ien1, ien2;

#ifdef DEBUG_GPIO
    // TEMP
    P1_0 = 1;  /************************************************************************BLE 自带 与电源控制功能冲突*******/
#endif // DEBUG_GPIO
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    HAL_ASSERT( HAL_INTERRUPTS_ARE_ENABLED());
    HAL_DISABLE_INTERRUPTS();

    // check if radio allows sleep, and if so, preps system for shutdown
    // 检查radio 是否需允许进入低功耗,如果允许,提前进入低功耗状态 
    if ( halSleepPconValue && ( LL_PowerOffReq(halPwrMgtMode) == LL_SLEEP_REQUEST_ALLOWED ) )
    {
      
      
      /**************************************************************************************************************************/
      /*  加入电源控制  此后进入低功耗状态  电平拉低 P1_0 =1 */
      
      
      /**************************************************************************************************************************/
      
      
      
#if ((defined HAL_KEY) && (HAL_KEY == TRUE))
      // get peripherals ready for sleep
      HalKeyEnterSleep();
#endif // ((defined HAL_KEY) && (HAL_KEY == TRUE))

#ifdef HAL_SLEEP_DEBUG_LED
      HAL_TURN_OFF_LED3();
#else
      // use this to turn LEDs off during sleep
      HalLedEnterSleep();
#endif // HAL_SLEEP_DEBUG_LED

      // enable sleep timer interrupt
      if (timeout != 0)    // 设置休眠时间 
      {
        // check if the time to next wake event is greater than max sleep time
        if (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 amount
          halSleepSetTimer( sleepTimer, timeout );
        }
      }

      // prep CC254x power mode
      HAL_SLEEP_PREP_POWER_MODE(halPwrMgtMode);  // 模式设置 这里进入的PM2 

      // save interrupt enable registers and disable all interrupts
      HAL_SLEEP_IE_BACKUP_AND_DISABLE(ien0, ien1, ien2);
      HAL_ENABLE_INTERRUPTS();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
#ifdef DEBUG_GPIO
      // TEMP
      P1_0 = 0;
#endif // DEBUG_GPIO

      // 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();

#ifdef DEBUG_GPIO
      // TEMP
      P1_0 = 1;  /************************************************************************BLE 自带 与电源控制功能冲突*******/
#endif // DEBUG_GPIO

      // 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 registers
      HAL_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_LED
      HAL_TURN_ON_LED3();
#else //!HAL_SLEEP_DEBUG_LED
      // use this to turn LEDs back on after sleep
      HalLedExitSleep();
#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();
  }

#ifdef DEBUG_GPIO
      // TEMP
      P1_0 = 0;
#endif // DEBUG_GPIO

  return;
}


 

 

跳出低功耗模式在此程序里是sleep timer 时间溢出,也就是在中断里退出低功耗模式

/*******************************************************************************
 * @fn          halSleepTimerIsr
 *
 * @brief       Sleep timer ISR.
 *
 * input parameters
 *
 * None.
 *
 * output parameters
 *
 * @param       None.
 *
 * @return      None.
 */
HAL_ISR_FUNCTION(halSleepTimerIsr, ST_VECTOR)
{
  HAL_ENTER_ISR();

  HAL_SLEEP_TIMER_CLEAR_INT();

#ifdef HAL_SLEEP_DEBUG_POWER_MODE
  halSleepInt = TRUE;
#endif // HAL_SLEEP_DEBUG_POWER_MODE
   ///////////////////////////////////////////////////////////////////////////////////////////// 拉高
  
  
///////////////////////////////////////////////////////////////////////////////////////////////////
  CLEAR_SLEEP_MODE();// 所有的任务退出Sleep模式时,调用CLEAR_SLEEP_MODE();

  HAL_EXIT_ISR();

  return;
}


 

 

 

你可能感兴趣的:(BLE,CC2541,低功耗模式)