Tickless idle mode and wakeup interrupts

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. 1. I am using SW timers as well along with the tickless idle mode, therefore is it safe to assume that eTaskConfirmSleepModeStatus() always returns either eAbortSleep or eStandardSleep ? 2. 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(STM32L152DiscoveryIAR) 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(uint32t xExpectedIdleTime ) { if (xExpectedIdleTime > maximumsuppressibleticks) { xExpectedIdleTime = maximumsuppressibleticks; } /* * Calculate the reload value required to wait xExpectedIdleTime tick periods. */ uint32t reloadvalue = xExpectedIdleTime * reloadvalueforonetick; /* * TODO: Any compensation for the time the timer is stopped */ /* * Stop the timer momentarily */ HALLPTIMCounterStopIT(&lptimhandle); /* * 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.

Tickless idle mode and wakeup interrupts

  1. I am using SW timers as well along with the tickless idle mode, therefore is it safe to assume that |eTaskConfirmSleepModeStatus()| always returns either |eAbortSleep| or |eStandardSleep| ?
I don’t think the behaviour or eTaskConfirmSleepModeStatus() will change if you have software timers – but eStandardSleep is not one of the values it returns – is this just a mistype or did you get the code from somewhere other than us?
  1. 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(STM32L152DiscoveryIAR) 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).
If interrupts were enabled before going to sleep you would get into a race condition as an interrupt may occur that unblocks a task, then you would enter sleep mode when you shouldn’t. The hardware is designed to avoid this – hence when you sleep with interrupts disabled an interrupt will still bring the MCU out of sleep mode BUT the interrupt will not actually execute until you enable interrupts again.

Tickless idle mode and wakeup interrupts

Hi Richard, Thanks for the answer.
I am using SW timers as well along with the tickless idle mode, therefore is it safe to assume that |eTaskConfirmSleepModeStatus()| always returns either |eAbortSleep| or |eStandardSleep| ?
I don’t think the behaviour or eTaskConfirmSleepModeStatus() will change if you have software timers – but eStandardSleep is not one of the values it returns – is this just a mistype or did you get the code from somewhere other than us?
I am using the official FreeRTOS port and this is what is in the task.h file. ~~~ /* Possible return values for eTaskConfirmSleepModeStatus(). / typedef enum { eAbortSleep = 0, / A task has been made ready or a context switch pended since portSUPPORESSTICKSAND_SLEEP() was called – abort entering a sleep mode. */ eStandardSleep, /* Enter a sleep mode that will not last any longer than the expected idle time. */ eNoTasksWaitingTimeout /* No tasks are waiting for a timeout so it is safe to enter a sleep mode that can only be exited by an external interrupt. */ } eSleepModeStatus; ~~~ If the behaviour of what eTaskConfirmSleepModeStatus() returns does not change depending on the usage of software timers I think we’re fine.
If interrupts were enabled before going to sleep you would get into a race condition as an interrupt may occur that unblocks a task, then you would enter sleep mode when you shouldn’t. The hardware is designed to avoid this – hence when you sleep with interrupts disabled an interrupt will still bring the MCU out of sleep mode BUT the interrupt will not actually execute until you enable interrupts again.
Thanks for the explanation, Richard. I now understand the rationale behind the chunk of code there. I think I have found the relevant information in the chip datasheet as well. It’s as follows.
Some embedded systems might have to execute system restore tasks after the processor wakes up, and before it executes an interrupt handler. To achieve this set the PRIMASK bit to 1 and the FAULTMASK bit to 0. If an interrupt arrives that is enabled and has a higher priority than current exception priority, the processor wakes up but does not execute the interrupt handler until the processor sets PRIMASK to zero. For more information about PRIMASK and FAULTMASK see Exception mask registers on page 22.
So, I assume still this would take BASEPRI value into consideration and would execute instructions untile the interrupts are re-enabled and would execute the ISR afterwards. So, ideally the above code (vPortSuppressTicksAndSleep) should work without enabling the interrupts then. Just another question specially regarding the use of low power timer(LPTIM) for tickless idle mode with deep sleeping. I know this is going to be a bit chip specific rather than RTOS related, but I would like to hear from anyone with similar experience. The current STM32 datasheet for LPTIM mentions that* reading counter register is not reliable and it should be read consecutively until they become identical to assert that it is a valid counter read*. I’m using LPTIM for my time base in tickless idle implementation and actually relying on the value of counter register in time adjustment calculation. As of my current observation, the entire implementation is quite unreliable and I notice a slippage in time when using LPTIM with RTOS tickless mode to transition to STOP2. Does anyone have success using LPTIM with tickless idle, or the above extract from datasheet is sufficient to suggest that LPTIM can not be used as a time base with tickless idle mode. Any way to isolate the issues, I’m currently in the process of using tickless idle with a GP timer (but of course then I have another issue of not being able to use STOP modes and have to go to SLEEP mode instead, which further raises concerns about the power budget). I highly appreciate your thoughts on this. Thank you in advane.

Tickless idle mode and wakeup interrupts

A few comments on the STM32 LPTIM and the issues you are seeing (I am currently studying the part for a project). My understanding of the reading issue is that the LPTIM counter is likely implemented on a different clock domain that used to read it, and the timer uses ‘slow’ gates to save power, so if you read the counter value at the same time as it is incrementing, then the value returned might have some new bits and some old bits. The only way to tell that this happened is to read it twice. If you get the same value, then the read was good, if not, then one of them is bad, but you have no idea which one, so you need to keep on reading. When you get consistant values you stop and use it. (There is also a mode where the read resets the value, so you can’t read it again, which says that basically you can’t tell if the number is accurate, not sure how useful that mode is). Also, some slipage of time when using tickless idle is totally expected. Time measured by the LPTimer is by necessity much less accurate because it is slower, and there is a bit of inaccuracy in switching from one timer to another. You really should only be going into tickless idle when you don’t have something that needs accurate timing happening anyway. One other option to keep a more accurate long term timebase is to setup the RTC to provide the long term timing, and compare its idea of what time it is to what the high speed timer says when coming out of tickless idle and make the correction based on it.

Tickless idle mode and wakeup interrupts

Thanks for the reply, Richard. I understand the slipage is unavoidable, but the slipage I was experiencing is quite noticeable from the very start(I even don’t think it was accumulating over time). I will give more details on this once I happen to successfully use tickless idle mode with a normal GPIO timer(which is my plan as of now). I will consider on RTC compensation as well. Actually we don’t rely on the absolute time, but only software delays. So, as per your observations do you assume that LPTIM can be used as the tick source for tickless idle mode inspite of the unreliable counter readings. Or are you thinking of using some other tick source and using LPTIM purely as a wakeup source to interrupt the processor after going to STOP mode ? Thank you.

Tickless idle mode and wakeup interrupts

The LPTIM appears to be able to be read relaibly by doing the multiple reads suggested in the documentation.
Read & Save, Read Again, if same then is a good read. If not, save and repeat until you get two readings in the row the same. This should get you a reliable reading, it may just take a couple of readings (but it shouldn’t need too many).

Tickless idle mode and wakeup interrupts

Hi Richard, Thanks for the feedback. I will try to use LPTIM as a ticksource and will definietely let you know the progress of this.

Tickless idle mode and wakeup interrupts

Hi Amila, I would very much appreciate if you could share your findigs of using LPTIM as a tick source for the STM32 in tickless idle mode. I am facing exactly the same issue as you described above, trying to get this running using LPTIM since several days. Thanks! Michael

Tickless idle mode and wakeup interrupts

Another thing that I have been using is use the LPTIM as my main tick source (instead of the build in Systic) and running with a prescaler of 32 so the base frequency of the timer is 1024 Hz, this can get you close to a 1ms tick if you really want that fast or with a divide by 10, about a 10ms tick. It also says that if you want to go tickless, you can set the trigger to up to just over a minute in the future. (raising the prescaler to 256 give a 128 Hz clock, giving a base interrupt rate of about 8 ms, and a tickless limit of about 8 minutes. I haven’t tried writing actual tickless code to handle this (working on other parts of the system) but it looks like by always using the the same timer for tick and tickless modes looks like it may have some advantages. One idea is that if you wake up from some other interrupt, you can set the timer trigger to a futer multiple of the base tick rate, you can avoid the normal tickless slips.