FreeRTOS tickless mode with low power timer(LPTIM)

amilaperera wrote on Tuesday, December 04, 2018:

Hi,

I’ve already posted regarding wakeup interrupts in tickless mode to clear out certain things last week.
https://sourceforge.net/p/freertos/discussion/382005/thread/30a858262f/

With all that valuable input, currently I’m trying to use LPTIM on STM32L475 chip as the RTOS tick source to enable FreeRTOS tickless idle mode. I’ve configured lptim to be clocked by the LSE(32768Hz) and have configured the prescaler and counter to get a tick once nearly in 1(ms). Of course, this accuracy is not an issue for now.

I’m currently having an issue with the LPTIM so that when it comes out from Sleep/Stop mode, the pending tick interrupt does not fire as soon as I re-enable the interrupts. This doesn’t happen when I try the same tickless mode with a general purpose timer(eg: TIM2). Due tho this issue, my ticksuppression function is not behaving in the way I want.
Does anyone have any thoughts on this ? Why this behaviour is different from TIM to LPTIM ?

Below, is my tick suppression function.

void vPortSuppressTicksAndSleep(uint32_t xExpectedIdleTime ) {
  uint32_t ulCompleteTickPeriods;
  TickType_t xModifiableIdleTime;
  if (xExpectedIdleTime > maximum_suppressible_ticks) {
    xExpectedIdleTime = maximum_suppressible_ticks;
  }

  uint32_t ulCounterValue = xExpectedIdleTime * ulPeriodValueForOneTick;

  __disable_irq();

  ucTickFlag = pdFALSE;

  eSleepModeStatus sleep_action = eTaskConfirmSleepModeStatus();
  if (sleep_action == eAbortSleep) {
    __enable_irq();

  } else if (sleep_action == eNoTasksWaitingTimeout){
    HAL_LPTIM_Counter_Stop_IT(&lptim1);
    configPRE_STOP_PROCESSING();
    HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI);
    configPOST_STOP_PROCESSING();
    // Restart tick
    HAL_LPTIM_Counter_Start_IT(&lptim1, ulPeriodValueForOneTick);
    // Re-enable interrupts
    __enable_irq();
  } else {
    HAL_LPTIM_Counter_Stop_IT(&lptim1);
    ucTickFlag = pdFALSE;

    /* underflow/overflow trapping is omitted */

    HAL_LPTIM_Counter_Start_IT(&lptim1, ulCounterValue);

    xModifiableIdleTime = xExpectedIdleTime;
    configPRE_STOP_PROCESSING();

    if (xModifiableIdleTime > 0) {
      HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI);
    }

    configPOST_STOP_PROCESSING();

    __enable_irq();

#if 0
    volatile auto x = __HAL_LPTIM_GET_IT_SOURCE(&lptim1, LPTIM_IT_ARRM);
    //configASSERT(x != 0);
    if (x != 0) {
    	ucTickFlag = pdTRUE;
    }
#endif
    HAL_LPTIM_Counter_Stop_IT(&lptim1);
    /* retrieve counter value from LPTIM */
    uint32_t ulCounterValue{0}, temp{0};
    {
      /* multiple readings are done to get a reliable counter register reading as described in the datasheet */
      do {
        temp = HAL_LPTIM_ReadCounter(&lptim1);
        ulCounterValue = HAL_LPTIM_ReadCounter(&lptim1);
      } while (temp != ulCounterValue);
    }
    if (ucTickFlag != pdFALSE) {
      /* Woken up by the LPTIM1 tick interrupt */

      /* Reloading the counter with the remaining ticks omitted - slow clock */

      ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
      HAL_LPTIM_Counter_Start_IT(&lptim1, ulPeriodValueForOneTick);
    } else {
       /* Woken up by some other interrupt */
      ulCompleteTickPeriods = ulCounterValue/ulPeriodValueForOneTick;
      ulCounterValue %= ulPeriodValueForOneTick;
      lptim1.Instance->CNT = 0;
      HAL_LPTIM_Counter_Start_IT(&lptim1, ulCounterValue);
    }

    /* Wind the tick forward by the number of tick periods that the CPU
     remained in a low power state. */
    vTaskStepTick(ulCompleteTickPeriods);

  }
}

ucTickFlag is set to pdTRUE in the LPTIM tick interrupt. The above function as you can understand, does not use STOP mode(but that’s what I want to achieve eventually), but still the problem I’m describing is evident even I use SLEEP mode.
Please notice that my application relies on FreeRTOS timers, therefore the sleep_action alwasy ends up being eStandardSleep which is correct.

Thank you.