Creating a VLLS1 Deep Sleep Mode with LPTMR

Document created by Pablo Noriega Navarro Employee on Jun 21, 2016Last modified by Pablo Noriega Navarro Employee on Oct 13, 2016
Version 8Show Document
  • View in full screen mode

The MCU in the KW40/30Z has various available very low power modes. In these power modes, the chip goes to sleep to save power, and it is not usable during this time (it can however receive different kinds of interruptions that could wake it up). The very low power modes supported by the microcontroller are:

 

VLPM.PNG

 

The KW40Z connectivity software stack has 6 predetermined deep sleep modes. These deep sleep modes have different configurations for the microcontroller low power mode, the BLE Link Layer state and in which ways the device can be awaken. These predetermined DSM (Deep Sleep Modes) are:

 

DSMs.PNG

* VLLS0 if DCDC is bypassed. VLLS1 with either Buck or Boost.

** Available in Buck mode only.

 

Having said that, if you want the lowest possible consumption by the MCU, while also being able to wake up your application automatically with a timer (achieved with VLSS1), there is no DSM available. You can, however, create your own Deep Sleep Mode with low power timers enabled. Please note that VLSS1 has the lowest possible consumption when using a DCDC converter. When in bypass mode, the lowest possible consumption is achieved with VLSS0.

 

To create your Deep Sleep Mode, you should start with the function that will actually handle the board going into deep sleep. This should be done in the PWR.c file, along with the rest of the DSM handler functions. This function is quite similar to the ones already made for the other deep sleep modes. Link layer interruptions, timer settings and the low power mode for the MCU are handled here.

 

/* PWR.c */

#if (cPWR_UsePowerDownMode)
static void PWR_HandleDeepSleepMode_7(void)
{
 
#if cPWR_BLE_LL_Enable
  uint16_t bleEnabledInt;
#endif

  uint8_t clkMode;
  uint32_t lptmrTicks;
  uint32_t lptmrFreq;
 
  PWRLib_MCU_WakeupReason.AllBits = 0;
 
#if cPWR_BLE_LL_Enable 
  if(RSIM_BRD_CONTROL_BLE_RF_OSC_REQ_STAT(RSIM)== 0) // BLL in DSM
  {
    return;

  bleEnabledInt = PWRLib_BLL_GetIntEn();
  PWRLib_BLL_ClearInterrupts(bleEnabledInt);   
  PWRLib_BLL_DisableInterrupts(bleEnabledInt);
#endif
 
  if(gpfPWR_LowPowerEnterCb != NULL)
  {
    gpfPWR_LowPowerEnterCb();
  }
 
  /* Put the device in deep sleep mode */
#if cPWR_DCDC_InBypass 
  PWRLib_MCU_Enter_VLLS0();
#else
  PWRLib_MCU_Enter_VLLS1();
#endif
 
  if(gpfPWR_LowPowerExitCb != NULL)
  {
    gpfPWR_LowPowerExitCb();
  }
 
#if cPWR_BLE_LL_Enable 
  PWRLib_BLL_EnableInterrupts(bleEnabledInt);       
#endif 
 
  PWRLib_LPTMR_ClockStop();
 
}
#endif /* #if (cPWR_UsePowerDownMode) */

 

Remember to add this function to the deep sleep handler function array:

 

/* PWR.c */

const pfHandleDeepSleepFunc_t maHandleDeepSleep[]={PWR_HandleDeepSleepMode_1,
                                                    PWR_HandleDeepSleepMode_2,
                                                    PWR_HandleDeepSleepMode_3,
                                                    PWR_HandleDeepSleepMode_4,
                                                    PWR_HandleDeepSleepMode_5,
                                                    PWR_HandleDeepSleepMode_6,
                                                    PWR_HandleDeepSleepMode_7
                                                   };

 

This function should allow your device to go to sleep. It does the strictly necessary things before the device goes to sleep: disables link layer interruptions, gets the configuration for the low power timer and it starts the timer. Please note that when the board is in either Buck or Boost DCDC mode, only VLSS1 is supported. When the device is in bypass mode, VLSS0 can be chosen.

 

Now that the deep sleep handler is done, there are some changes that have to be made to have a proper execution. In the PWR_Configuration.h file, for example, there is an error message when the parameter cPWR_DeepSleepMode is larger than 6 (the default DSM modes), but, since you have added a new deep sleep mode, this number should be changed to 7:

 

#if (cPWR_DeepSleepMode > 7 )  // default: 6
  #error "*** ERROR: Illegal value in cPWR_DeepSleepMode"
#endif

 

Other changes that have to be made are the Low Leakage Wake Up unit and the deep sleep mode configurations. To change the LLWU configuration, you should add a case for the new deep sleep mode in the PWRLib_ConfigLLWU() function:

 

/* PWRLib.c */

void PWRLib_ConfigLLWU( uint8_t lpMode )
{
  switch(lpMode)
  {
  case 1:
    LLWU_ME = gPWRLib_LLWU_WakeupModuleEnable_BTLL_c | gPWRLib_LLWU_WakeupModuleEnable_LPTMR_c;
  break;
  case 2:
    LLWU_ME = gPWRLib_LLWU_WakeupModuleEnable_BTLL_c;
  break;
  case 3:
    LLWU_ME = gPWRLib_LLWU_WakeupModuleEnable_LPTMR_c | gPWRLib_LLWU_WakeupModuleEnable_DCDC_c;
  break;
  case 4:
  case 5:
    LLWU_ME = gPWRLib_LLWU_WakeupModuleEnable_DCDC_c; 
  break;
  case 6:
    LLWU_ME = 0;
  break;
  case 7: /* The new deep sleep mode can be awaken through a Low Power Timer timeout */
    LLWU_ME = gPWRLib_LLWU_WakeupModuleEnable_LPTMR_c;
  break;
  }
} 
}
#endif /* #if (cPWR_UsePowerDownMode) */

 

Once this case has been added, you should change the function that calls PWRLib_ConfigLLWU(), PWRChangeDeepSleepMode():

 

/* PWR.c */

bool_t PWR_ChangeDeepSleepMode (uint8_t dsMode)
{
#if (cPWR_UsePowerDownMode)

  if(dsMode > 7) //Since you’ve added an extra DSM, this is now 7 (default: 6)
  {
     return FALSE;
  }
  
PWRLib_SetDeepSleepMode(dsMode);
PWRLib_ConfigLLWU(dsMode);

#if (cPWR_BLE_LL_Enable) 
  PWRLib_BLL_ConfigDSM(dsMode);
  PWRLib_ConfigRSIM(dsMode);
#endif 
 
return TRUE;
 
#else
  return TRUE;

#endif  /* #if (cPWR_UsePowerDownMode) */
}

 

Now, since you’ll be using a Low Power Timer, you should modify the maLPModeUseLPTMR[] constant in the PWRLib.c file, indicating that you will use a low power timer:

 

/* PWRLib.c */

const uint8_t maLPModeUseLPTMR[]={0,1,1,1,0,0,1,1}; //We add the last 1. default: {0,1,1,1,0,0,1}

 

You should add a case for your new low power mode in the PWRLib_ConfigRSIM(). Here you will handle the BLE link layer whilst the device is in low power mode. This function can be found in the PWRLib.c file:

 

/* PWRLib.c */

void PWRLib_ConfigRSIM( uint8_t lpMode )
{
  switch(lpMode)
  {
  case 1:
  case 2:
      RSIM_BWR_CONTROL_STOP_ACK_OVRD_EN(RSIM, 0);
      RSIM_CONTROL |= RSIM_CONTROL_BLE_RF_OSC_REQ_EN_MASK | RSIM_CONTROL_BLE_RF_OSC_REQ_INT_EN_MASK | RSIM_CONTROL_BLE_RF_OSC_REQ_INT_MASK;
    break;
  case 3:
  case 4:
  case 5:
      RSIM_CONTROL &= ~(RSIM_CONTROL_STOP_ACK_OVRD_EN_MASK | RSIM_CONTROL_BLE_RF_OSC_REQ_EN_MASK | RSIM_CONTROL_BLE_RF_OSC_REQ_INT_EN_MASK);
      RSIM_CONTROL |= RSIM_CONTROL_BLE_RF_OSC_REQ_INT_MASK;
    break;
  case 6:
      RSIM_CONTROL &= ~(RSIM_CONTROL_STOP_ACK_OVRD_EN_MASK  | RSIM_CONTROL_BLE_RF_OSC_REQ_INT_EN_MASK);
      RSIM_CONTROL |= RSIM_CONTROL_BLE_RF_OSC_REQ_INT_MASK | RSIM_CONTROL_BLE_RF_OSC_REQ_EN_MASK;
    break;
  case 7: //@PNN
      RSIM_CONTROL &= ~(RSIM_CONTROL_STOP_ACK_OVRD_EN_MASK | RSIM_CONTROL_BLE_RF_OSC_REQ_EN_MASK | RSIM_CONTROL_BLE_RF_OSC_REQ_INT_EN_MASK);
      RSIM_CONTROL |= RSIM_CONTROL_BLE_RF_OSC_REQ_INT_MASK;
    break;
  }
}

 

Your low power mode awaken by a low power timer should now be ready. To change the deep sleep mode and the time the device will be in deep sleep mode before it is awaken, use these functions in your application:

 

PWR_ChangeDeepSleepMode(7);         
                 
       
  /* Change deep sleep mode */

PWR_SetDeepSleepTimeInMs(YOUR_DEEP_SLEEP_TIME_IN_MS);    
      /* Time the device will spend on deep sleep mode */

PWR_AllowDeviceToSleep();                                     
/* Allows the device to go to deep sleep mode */

PWR_DisallowDeviceToSleep();                           
      
/* Does not allows the device to go to deep sleep mode */

4 people found this helpful

Attachments

    Outcomes