In Freertos tickless mode,software timer callback function can wakeup system or not?

The version I’m using is 10.3.1. use Lptimer as tick source. STM32L4 stop2 lowpower mode.
I was wondering Freertos in tickless mode with use software timer, that software timer callback can wakeup system or not?

With the default tickless implementation provided by FreeRTOS, software timers don’t count time during STOP2 thus will not wake the system from STOP2. That’s because the SysTick timer stops operating during STOP2 (SLEEPDEEP).

However, you can use a custom tickless implementation that moves the system tick to a timer that keeps running in STOP2. For example, lptimTick.c provides the tick from LPTIM. With LPTIM providing the tick, software timers will wake the system from STOP2.

I have implemented the custom tickless mode and it works normally. What is the reason why the software timer cannot wake up overtime

this is my code, i use vTaskStepTick( ulCompleteTickPeriods ); to compensate ticks.

#if( configUSE_TICKLESS_IDLE == 2 )

void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
  uint32_t ulReloadValue, ulCompleteTickPeriods, ulCount;
  eSleepModeStatus eSleepAction;


	/* Make sure the LPTIM reload value does not overflow the counter. */
	if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks )
		xExpectedIdleTime = xMaximumPossibleSuppressedTicks;

	/* Calculate the reload value required to wait xExpectedIdleTime tick periods. */
  ulReloadValue = (ulReloadValueForOneSec * (xExpectedIdleTime - 1UL))/configTICK_RATE_HZ;
	ulCount = HAL_LPTIM_ReadCounter(&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" );

	/* The tick flag is set to false before sleeping.  If it is true when sleep
	mode is exited then sleep mode was probably exited because the tick was
	suppressed for the entire xExpectedIdleTime period. */
	ulTickFlag = 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. */
	eSleepAction = eTaskConfirmSleepModeStatus();
	if( eSleepAction == eAbortSleep )
		/* Restart tick and continue counting to complete the current time
		slice. */
                __HAL_LPTIM_ENABLE_IT(&LptimHandle, LPTIM_IT_ARRM);
                __HAL_LPTIM_AUTORELOAD_SET(&LptimHandle, ulCount);
                __HAL_LPTIM_COMPARE_SET(&LptimHandle, (ulCount/2));
		/* Re-enable interrupts  */
		__asm volatile ( "cpsie i" );
		/* Start LPTIM Timeout wake up based on expected idle time */
		HAL_LPTIM_TimeOut_Start_IT(&LptimHandle, 0xFFFF, ulReloadValue);
		/* A user definable macro that allows application code to be inserted
		here.  Such application code can be used to minimise power consumption
		further by turning off IO, peripheral clocks, the Flash, etc. */

		/* There are no running state tasks and no tasks that are blocked with a
		time out.  Assuming the application does not care if the tick time slips
		with respect to calendar time then enter a deep sleep that can only be
		woken by (in this demo case) the user button being pushed on the
		STM32L discovery board.  If the application does require the tick time
		to keep better track of the calendar time then the LPTIM peripheral can be
		used to make rough adjustments. */
		/* Enter STOP 1 mode */
		/* A user definable macro that allows application code to be inserted
		here.  Such application code can be used to reverse any actions taken
		by the configPRE_STOP_PROCESSING().  In this demo
		configPOST_STOP_PROCESSING() is used to re-initialise the clocks that
		were turned off when STOP mode was entered. */
		ulCount = HAL_LPTIM_ReadCounter(&LptimHandle);


		/* Re-enable interrupts */
                __asm volatile ( "cpsie i" );
                if( ulTickFlag != pdFALSE )
			ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
                        __HAL_LPTIM_ENABLE_IT(&LptimHandle, LPTIM_IT_ARRM);
                        __HAL_LPTIM_AUTORELOAD_SET(&LptimHandle, ulReloadValueForOneTick);
                        __HAL_LPTIM_COMPARE_SET(&LptimHandle, (ulReloadValueForOneTick/2));
			ulCompleteTickPeriods = (ulCount * configTICK_RATE_HZ)/ ulReloadValueForOneSec;
			ulReloadValue = (ulReloadValueForOneTick - ( ulCompleteTickPeriods % ulReloadValueForOneTick ));
                        __HAL_LPTIM_ENABLE_IT(&LptimHandle, LPTIM_IT_ARRM);
                        __HAL_LPTIM_AUTORELOAD_SET(&LptimHandle, ulReloadValue);
                        __HAL_LPTIM_COMPARE_SET(&LptimHandle, (ulReloadValue/2));
		/* update HAL base time */
		uwTick += ulCompleteTickPeriods;
		/* Wind the tick forward by the number of tick periods that the CPU
		remained in a low power state. */
		vTaskStepTick( ulCompleteTickPeriods );

If your tickless mode is implemented correctly, then the time at which the software timer needs to execute should generate an interrupt - the interrupt will then bring the system out of sleep mode. So software timers should bring the system out of sleep mode, but only indirectly.

When you enter sleep mode you reprogram the clock to generate an interrupt at the time the next task wants to run (the nearest task unblock time) - and software timers run in a task so there is no difference between knowing the time at which a call to vTaskDelay() expires, and the time at which a software timer expires.

For example:

  1. If a software timer with a period of 1000ms expires, the timer task runs to execute the timer’s callback, then re-enters the Blocked state for 1000ms (assuming there are no other software timers).

  2. TaskA runs after the timer task. It calls vTaskDelay( pdMS_TO_TICKS( 2000 ) );

Now you have one task that wants to execute in 1000ms time, and another that wants to execute in 2000ms time. 1000ms is the nearest time, so, if there are no other tasks in the system you will enter sleep mode by first programming your low power clock to generate an interrupt in 1000ms time, then sleep. In 1000ms time, the interrupt executes, bringing the system out of sleep mode at exactly the time the software time wants to execute its callback function again.

If you have software timers, then the timer task will be running and will block with a delay of the time till the next timer event. so if you have a software timer programmed to wake you up, the timer task will be delayed to that time, so the tickless idle should set the maximum time to run for that time so you should wake up. The fact that YOUR tasks are using an event group won’t affect the software timer operation.

Either you didn’t set your LPTimer to continue to run in the stop mode or your tick-less code didn’t set the timer properly to wake you up in that time period.

I’ve tested your example, It works exactly as you said.
But in my project, I use event groups to block all tasks, That is, none of the tasks are running. Just leave one software timer, As a result, the software timer cannot wake up the system and execute its callback function.

I have implemented Tickless Mode and it works fine.Use vTaskDelay(1000); It can also wake up normally.
I turned on a software timer when all the tasks in the system were blocked (or no tasks were created), and the timer didn’t wake up properly .

Can you set configUSE_TICKLESS_IDLE to 1 and test again? Just trying to help you divide and conquer to produce a diagnosis.