cancel
Showing results for 
Search instead for 
Did you mean: 

ThreadX tickless mode, can't get into Sleep mode

paolog
Associate III

I have problems in getting this working. I moved from FreeRTOS to Azure RTOS, and I found out that in general there's lot less information on this RTOS. So I've been looking into the few resources, but I'm afraid I'm missing some important points. Articles in knowledge base show how to manage low power mode in ThreadX, but don't cover tickless mode (while an article about tickless mode is available for FreeRTOS). Examples in CubeMX repository are very simple. I also don't have much experience on STM32U5, and this doesn't help... I'm using CubeMX and HAL functions, IDE is STM32CubeIDE (current versions). Here's the problem:

I'm using ThreadX kernel running at 1 kHz, low power and tickless mode enabled. Two timers, one every 10 ms and another every 250 ms. RTC is interrupting every second, DMA2D interrupt also firing when LCD is updated. TDC is used for the LCD. Threads are waiting on events to perform some actions.Here are partial definitions of the functions related to low power management.

 

void App_ThreadX_LowPower_Timer_Setup(ULONG count)
{
  /* USER CODE BEGIN  App_ThreadX_LowPower_Timer_Setup */
  // Setup LPTIM4 to wakeup after (ticks * 1000) / TX_TIMER_TICKS_PER_SECOND ms
  HAL_LPTIM_DeInit(&hlptim4);
  hlptim4.Init.Period = LPTIM_MS_TO_TICK((count * 1000) / TX_TIMER_TICKS_PER_SECOND) - 1;
  HAL_LPTIM_Init(&hlptim4);
  /* USER CODE END  App_ThreadX_LowPower_Timer_Setup */
}

void App_ThreadX_LowPower_Enter(void)
{
  /* USER CODE BEGIN  App_ThreadX_LowPower_Enter */
  HAL_SuspendTick();

  // LPTIM4 used to wake up after the designated time
  HAL_LPTIM_SetOnce_Start_IT(&hlptim4, LPTIM_CHANNEL_1);

  // Enter sleep mode
  HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);

  // *** DOESN'T GO TO SLEEP MODE!!! ***

  /* USER CODE END  App_ThreadX_LowPower_Enter */
}

void App_ThreadX_LowPower_Exit(void)
{
  /* USER CODE BEGIN  App_ThreadX_LowPower_Exit */
  HAL_ResumeTick();
  /* USER CODE END  App_ThreadX_LowPower_Exit */
}

ULONG App_ThreadX_LowPower_Timer_Adjust(void)
{
  /* USER CODE BEGIN  App_ThreadX_LowPower_Timer_Adjust */
  ULONG actual_ticks_slept;
  ULONG elapsed_time_in_ms;

  // Determine how long the processor actually slept

  // Read counter and stop LPTIM
  actual_ticks_slept = HAL_LPTIM_ReadCounter(&hlptim4);
  // *** ALWAYS RETURNS 0 or 1 ***

  HAL_LPTIM_SetOnce_Stop_IT(&hlptim4, LPTIM_CHANNEL_1);
  elapsed_time_in_ms = LPTIM_TICK_TO_MS(actual_ticks_slept);

  /* Convert elapsed time to ThreadX ticks. */
  actual_ticks_slept = elapsed_time_in_ms / (1000 / TX_TIMER_TICKS_PER_SECOND);
  
  return(actual_ticks_slept);

  /* USER CODE END  App_ThreadX_LowPower_Timer_Adjust */
}

void HAL_LPTIM_AutoReloadMatchCallback(LPTIM_HandleTypeDef *hlptim) {
  // NEVER FIRES
  if (hlptim->Instance == LPTIM4) {
    HAL_LPTIM_SetOnce_Stop_IT(hlptim, LPTIM_CHANNEL_1);
  }
}

 

Of course I expect that RTC and DMA2D interrupts may interfere with the Sleep mode (they're happening at a slower rate compared to the kernel), but what happens is that the MCU never goes to sleep, even when i disable all the interrupts or if the LCD is not updated.

I noticed that ThreadX sets up the low power timer correctly to sleep few milliseconds, but it just doesn't happens.

My questions:

  • Is debug interfering with sleep mode? Should I use HAL_DBGMCU_EnableDBGSleepMode()?
  • If I insert HAL_PWR_EnableSleepOnExit() before entering Sleep mode should the MCU stay in sleep after servicing the interrupt?
  • Should I check and clear interrupt flags before entering Sleep mode? In this case, what would be the best way (HAL or LL way)?
  • Any idea about the reason why the MCU doesn't enter Sleep mode?

Any suggestion will be helpful, thank you.

5 REPLIES 5
Haithem Rahmani
ST Employee

Hi @paolog 

I think it is the SYSTICK interrupt that is waking up the system, the HAL_SuspendTick() is disabling the timebase TIMER interrupt not the SYSTICK.

PS: the SYSTICK is exclusively reserved for ThreadX.

regards
Haithem.

paolog
Associate III

Hi @Haithem Rahmani ,thank you for your reply.

Ok, that clarifies, I definitely got confused between the HAL tick and the SYSTICK. Does this mean that having a 1 ms timebase (1 tick = 1 ms) for the RTOS would make the function App_ThreadX_LowPower_Timer_Setup() unnecessary? The ms timer will never go off as the SYSTICK will wake the RTOS before that (sleeping 1 ms at maximum). Variable actual_ticks_slept would then become 1 at maximum (if no interrupt happen during 1 ms), correct?

 

Hi @paolog 

indeed, the TIMER won't work until the SYSTICK interrupt is disabled.

below the HAL_SuspendTick() implementation.

 

__weak void HAL_SuspendTick(void)
{
  /* Disable SysTick Interrupt */
  SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;
}

 

regards
Haithem.

paolog
Associate III

Thank you @Haithem Rahmani .

I will review my code about low power and see when the SYSTICK won't be needed, so the MCU will awaken by the HAL timer instead of SYSTICK (i.e. when it can sleep for more than 1 ms).

paolog
Associate III

Hi @Haithem Rahmani .

This feature is giving me hard times. Is there an example of ThreadX low power in tickless mode? Plenty of examples using FreeRTOS, but  I couldn't find anything comparable with ThreadX. Low power ThreadX examples don't cover tickless mode, surprising enough, as ST seems to be pushing ThreadX as first choice.

Thank you,

Paolo