AnsweredAssumed Answered

STM32L476 (nucleo) - FreeRTOS tickless (using LPTIM1)

Question asked by Fabio_IT on Nov 12, 2015
Hi guys,
I'm trying to use FreeRTOS in tickless mode using LPTIM1 as tick generator (1ms).
I followed the guide on the FreeRTOS webpage but still no luck until now, I mean, the MCU seems to enter the low-power state but vTaskDelay generates uncorrect timing.
I attach the code that I'm currently using, hoping someone can help figuring this out.

/* Define the function that is called by portSUPPRESS_TICKS_AND_SLEEP(). */
void vApplicationSleep( TickType_t xExpectedIdleTime )
{
  unsigned long ulLowPowerTimeBeforeSleep, ulLowPowerTimeAfterSleep;
  eSleepModeStatus eSleepStatus;
 
  /* Read the current time from a time source that will remain operational
  while the microcontroller is in a low power state. */
  ulLowPowerTimeBeforeSleep = (uint16_t) HAL_LPTIM_ReadCounter(&LptimHandle);
 
  /* Stop the timer that is generating the tick interrupt. */
    HAL_NVIC_DisableIRQ(LPTIM1_IRQn);
 
  /* Enter a critical section that will not effect interrupts bringing the MCU
  out of sleep mode. */
    __disable_irq();
 
  /* Ensure it is still ok to enter the sleep mode. */
  eSleepStatus = eTaskConfirmSleepModeStatus();
 
  if( eSleepStatus == eAbortSleep )
  {
    /* A task has been moved out of the Blocked state since this macro was
    executed, or a context siwth is being held pending.  Do not enter a
    sleep state.  Restart the tick and exit the critical section. */
    __enable_irq();
    HAL_NVIC_EnableIRQ(LPTIM1_IRQn);
    HAL_LPTIM_Counter_Start_IT(&LptimHandle, configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ);
  }
  else
  {
    if( eSleepStatus == eNoTasksWaitingTimeout )
    {
      /* It is not necessary to configure an interrupt to bring the
      microcontroller out of its low power state at a fixed time in the
      future. */
      HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
    }
    else
    {
      /* Configure an interrupt to bring the microcontroller out of its low
      power state at the time the kernel next needs to execute.  The
      interrupt must be generated from a source that remains operational
      when the microcontroller is in a low power state. */
            HAL_LPTIM_Counter_Start_IT(&LptimHandle, (configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ) * xExpectedIdleTime);
 
            HAL_NVIC_EnableIRQ(LPTIM1_IRQn);
             
      /* Enter the low power state. */
      HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
 
      /* Determine how long the microcontroller was actually in a low power
      state for, which will be less than xExpectedIdleTime if the
      microcontroller was brought out of low power mode by an interrupt
      other than that configured by the vSetWakeTimeInterrupt() call.
      Note that the scheduler is suspended before
      portSUPPRESS_TICKS_AND_SLEEP() is called, and resumed when
      portSUPPRESS_TICKS_AND_SLEEP() returns.  Therefore no other tasks will
      execute until this function completes. */
      ulLowPowerTimeAfterSleep = (uint16_t) HAL_LPTIM_ReadCounter(&LptimHandle);
 
      /* Correct the kernels tick count to account for the time the
      microcontroller spent in its low power state. */
      if( ulLowPowerTimeBeforeSleep > ulLowPowerTimeAfterSleep)
        vTaskStepTick( (ulLowPowerTimeBeforeSleep - ulLowPowerTimeAfterSleep) / 32 );
      else
        vTaskStepTick( (ulLowPowerTimeAfterSleep - ulLowPowerTimeBeforeSleep) /32);
    }
 
    /* Exit the critical section - it might be possible to do this immediately
    after the prvSleep() calls. */
     __enable_irq();
 
    /* Restart the timer that is generating the tick interrupt. */
    HAL_NVIC_EnableIRQ(LPTIM1_IRQn);
  }
}

Outcomes