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
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);
}
void LOWPWR_PostSwitch (void) {
PORT_SetPinMux(DEBUG_CONSOLE_RX_PORT, DEBUG_CONSOLE_RX_PIN, DEBUG_CONSOLE_RX_PINMUX);
while (!(kMCG_Pll0LockFlag & CLOCK_GetStatusFlags()));
CLOCK_SetPeeMode();
BOARD_InitDebugConsole();
}
void LOWPWR_SetWakeUp (void) {
LLWU_EnableInternalModuleInterruptWakup(LLWU, LLWU_LPTMR_IDX, true);
LLWU_SetExternalWakeupPinMode(LLWU, LLWU_WAKEUP_PIN_IDX, kLLWU_ExternalPinFallingEdge);
}
void LOWPWR_SwitchMode (void) {
SMC_PreEnterStopModes();
SMC_SetPowerModeLls(SMC);
SMC_PostExitStopModes();
}
void LLWU_IRQHandler(void)
{
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
if (LLWU_GetInternalWakeupModuleFlag(LLWU, LLWU_LPTMR_IDX))
{
vPortLptmrIsr();
}
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);
}
}