amilaperera wrote on Tuesday, November 27, 2018:
Sorry for my previous mail. I didn’t attach a subject. Resending the same content with an appropriate subject.
I am in the process of enabling RTOS tickless idle mode and have already made the necessary changes to replace systick with a low power timer tick as the first step.
I have couple of questions in this regard.
- I am using SW timers as well along with the tickless idle mode, therefore is it safe to assume that
eTaskConfirmSleepModeStatus()
always returns eithereAbortSleep
oreStandardSleep
? - I’m using STM32 LPTIM1 as my tick source (low power timer) and using
STOP2
mode when the tickless idle is triggered. Before going to sleep I assume that interrupts should be enabled so that the CPU can be woken up by the interrupts working in deep sleep mode(including the LPTIM1 tick interrupt). However in the examples provided with FreeRTOS package(STM32L152_Discovery_IAR) I notice that the interrupts are disabled before going to sleep mode and they are enabled when the processor is woken up by from deep sleep modes. I wonder how this can really happen ? Am I missing something here. To me it seems that the interrupts should be enabled just before gong to deep sleep mode as for the processor to be taken out from sleep mode(either tick interrupt or any other wake up source).
Please find my implementation of vPortSuppressTicksAndSleep()
. As my current observation, I need to enable interrupts just before going to stop2 mode to make it work.
Can anyone shed some light in this regard ?
void vPortSuppressTicksAndSleep(uint32_t xExpectedIdleTime ) {
if (xExpectedIdleTime > maximum_suppressible_ticks) {
xExpectedIdleTime = maximum_suppressible_ticks;
}
/*
* Calculate the reload value required to wait xExpectedIdleTime tick periods.
*/
uint32_t reload_value = xExpectedIdleTime * reload_value_for_one_tick;
/*
* TODO: Any compensation for the time the timer is stopped
*/
/*
* Stop the timer momentarily
*/
HAL_LPTIM_Counter_Stop_IT(&lptim_handle);
/*
* Enter a critical section but don't use the taskENTER_CRITICAL()
* method as that will mask interrupts that should exit sleep mode.
*/
__asm volatile( "cpsid i" );
__asm volatile( "dsb" );
__asm volatile( "isb" );
/*
* tick flag is set to false before going to sleep
*/
tick_flag = pdFALSE;
/*
* If a context switch is pending then abandon the low power entry as the
* context switch might have been pended by an external interrupt that requires
* processing.
*/
eSleepModeStatus sleep_action = eTaskConfirmSleepModeStatus();
if (sleep_action == eAbortSleep) {
/*
* Restart the tick
*/
HAL_LPTIM_Counter_Start_IT(&lptim_handle, reload_value_for_one_tick);
/*
* Re-enable the interrupts
*/
__asm volatile( "cpsie i" );
} else {
/*
* TODO: Need to update the tick count
*/
/*
* Restart the tick
*/
HAL_LPTIM_Counter_Start_IT(&lptim_handle, reload_value);
uint32_t modifiable_time = xExpectedIdleTime;
/*
* Check for nullness of power_manager_instance before operating on it.
* This is necessary to assure that we're not triggering the sleep mode processing
* before the controller creates the power_manager instance.
*/
if (power_manager_instance) {
/*
* Let the application carry out pre-sleep processing
*/
configPRE_SLEEP_PROCESSING(modifiable_time);
/*
* Sleep
*/
if (modifiable_time > 0) {
power_manager_instance->EnterLowPowerMode(marconi::controller::LowPowerMode::kStop2);
}
/*
* Let the application carry out post-sleep processing
*/
configPOST_SLEEP_PROCESSING(modifiable_time);
}
/*
* Stop low power timer.
* The time the clock is stopped for is not accounted here, since
* the clock is so slow. It is quite unlikely it is stopped for a complete count period.
*/
HAL_LPTIM_Counter_Stop_IT(&lptim_handle);
uint32_t count_after_sleep = HAL_LPTIM_ReadCounter(&lptim_handle);
/*
* Re-enable interrupts.
*/
__asm volatile( "cpsie i" );
__asm volatile( "dsb" );
__asm volatile( "isb" );
uint32_t complete_tick_periods = 0;
if (tick_flag != pdFALSE) {
/*
* Tick interrupt ended the sleep.
*/
complete_tick_periods = xExpectedIdleTime - 1UL;
HAL_LPTIM_Counter_Start_IT(&lptim_handle, reload_value_for_one_tick);
} else {
/*
* Something other than the tick interrupt ended the sleep.
*/
complete_tick_periods = count_after_sleep / reload_value_for_one_tick;
count_after_sleep %= reload_value_for_one_tick;
if (count_after_sleep == 0) {
count_after_sleep = reload_value_for_one_tick;
++complete_tick_periods;
}
HAL_LPTIM_Counter_Start_IT(&lptim_handle, count_after_sleep);
}
/*
* Wind the tick forward by the number of tick periods that the MCU remained in a low power state.
*/
vTaskStepTick(complete_tick_periods);
}
}
Thank you.