AnsweredAssumed Answered

Tickless Freertos and LLS mode

Question asked by whata on Jul 9, 2017
Latest reply on Jul 21, 2017 by whata

Hi, 

 

I'm attempting to implement an LLS mode in Freertos tickless operation. What i first did is I implemented the LLS mode in baremetal and verified that the MCU was entering the LLS mode (consuming around 2-3 uA) and was waking up correctly by the LLWU unit (via pin or lptrm). I then created a copy of: \boards\frdmkl26z\rtos_examples\freertos_tickless project which pretty much does the same thing wakes up either via lptmr or pin interrupt. 

 

I just extended the vPortSuppressTicksAndSleep function with code to properly enter the LLS mode without even touching clock settings or anything and it worked mostly as expected, the device could be woken up by an external interrupt or by timer timeout, except for one thing: Once the LLS was implemented the timing got all wrong and now 100 ticks are no longer 100ms but more like 50 seconds. How can that be? Is there a prescaler for LPTMR which gets magically modified somewhere?

 

Here's my additions to vPortSuppressTicksAndSleep 

 

               xModifiableIdleTime = xExpectedIdleTime;
               configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
               LOWPWR_PreSwitch();
               LOWPWR_SetWakeUp();
               LOWPWR_SwitchMode();
               LOWPWR_PostSwitch();
               if( xModifiableIdleTime > 0 )
               {

                    __asm volatile( "dsb" );
                    __asm volatile( "wfi" );
                    __asm volatile( "isb" );


               }
               configPOST_SLEEP_PROCESSING( xExpectedIdleTime );

 

And the implementation of functions called from  vPortSuppressTicksAndSleep 

 

/*!
* @brief This function must be executed prior to entering the LLS mode. Here we
*  wait for transmission completion on all devices, and then disable the used
*  peripherals and disable the pins to avoid unecessary current usage
*/

void LOWPWR_PreSwitch (void) {

    while (!(kLPSCI_TransmissionCompleteFlag & LPSCI_GetStatusFlags((UART0_Type *)BOARD_DEBUG_UART_BASEADDR)));
    DbgConsole_Deinit();
    PORT_SetPinMux(DEBUG_CONSOLE_RX_PORT, DEBUG_CONSOLE_RX_PIN, kPORT_PinDisabledOrAnalog);

}

/*!
* @brief This function must be executed after exiting the LLS mode. Here we
*  re-enable the peripherals which were disabled.
*/

void LOWPWR_PostSwitch (void) {
     /*
      * Re-enable the rx pin on the console
      */


     PORT_SetPinMux(DEBUG_CONSOLE_RX_PORT, DEBUG_CONSOLE_RX_PIN, DEBUG_CONSOLE_RX_PINMUX);

    /*
     * If enter stop modes when MCG in PEE mode, then after wakeup, the MCG is in PBE mode,
     * need to enter PEE mode manually.
     */

    while (!(kMCG_Pll0LockFlag & CLOCK_GetStatusFlags()));
    CLOCK_SetPeeMode();

    /* Re-enable console */

    BOARD_InitDebugConsole();

}

/*!
* @brief This function sets-up the wake-up for the microcontroller. The're are two sources
*  which are used for wake-up, a LPTMR interrupt and SW1 interrupt via the LLWU.
*/

void LOWPWR_SetWakeUp (void) {

    /* Set up LLWU to receive interrupts from LPTMR=0U */
    LLWU_EnableInternalModuleInterruptWakup(LLWU, LLWU_LPTMR_IDX, true);

    /* Set up LLWU to receive interrupt from pin=7U */
    LLWU_SetExternalWakeupPinMode(LLWU, LLWU_WAKEUP_PIN_IDX, kLLWU_ExternalPinFallingEdge);

}

/*!
* @brief This function enters the low power mode
*/

void LOWPWR_SwitchMode (void) {
    SMC_PreEnterStopModes();
    SMC_SetPowerModeLls(SMC);
    SMC_PostExitStopModes();
}


/*!
* @brief LLWU interrupt handler.
*/

void LLWU_IRQHandler(void)
{
     portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

    /* If wakeup by LPTMR. */
    if (LLWU_GetInternalWakeupModuleFlag(LLWU, LLWU_LPTMR_IDX))
    {
        vPortLptmrIsr();
    }

    /* If wakeup by external pin. */
    if (LLWU_GetExternalWakeupPinFlag(LLWU, LLWU_WAKEUP_PIN_IDX))
    {
        PORT_ClearPinsInterruptFlags(BOARD_SW1_PORT, (1U << BOARD_SW1_GPIO_PIN));
        LLWU_ClearExternalWakeupPinFlag(LLWU, LLWU_WAKEUP_PIN_IDX);

        xSemaphoreGiveFromISR(xSWSemaphore, &xHigherPriorityTaskWoken);
    }

}

Outcomes