Need clarifications about timer deamon

Recently, I added trace functionality to my project. I use the traceTASK_SWITCHED_IN and traceTASK_SWITCHED_OUT macros to set a DAC voltage to monitor the active task, as briefly explained here: FreeRTOS trace macros.
I added the trace to all my tasks but also to the IDLE and TIMER tasks to have a complete view of the system and CPU usage.
The strange thing is that I see that the TIMER task gets swiched in quite often, even if the timers I used are configured with a low rate (in the order of tens of seconds).

In the two images below, the timer task is indicated by a voltage of about 3 volts (lower voltages are associated with the lower-priority tasks that build the application).
The images are with two levels of zoom to appreciate the details of the runtime behavior (the second image is the zoomed version of the interval indicated by the red mark in the first).

To me, this looks weird because it is explicitly stated in the documentation that the timer “does not consume any processing time unless a timer has actually expired”. Therefore, I suspect I’m using it wrongly.

Could someone help with this?

Thank you,

Do you use xEventGroupSetBitsFromISR() - Set a bit (flag) or bits in an RTOS event group from an interrupt in your application ? This function defers some work to the timer task.
Given your tracing results are correct.

I believe that the documentation you state is wrong if I understand your question and the source correctly. Here is the main body of prvTimerTask:

    for( ; configCONTROL_INFINITE_LOOP(); )
        /* Query the timers list to see if it contains any timers, and if so,
         * obtain the time at which the next timer will expire. */
        xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );

        /* If a timer has expired, process it.  Otherwise, block this task
         * until either a timer does expire, or a command is received. */
        prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );

        /* Empty the command queue. */

Obviously, there is periodic CPU time required to poll the timer list for expired timers. Must, because those are software timers, not asynchronously triggered timers.

Yes, I do. It is definitely that because I use it in several places, and I see more of that behavior when there are a lot of calls to xEventGroupSetBitsFromISR()

Thank you!

Thank you,
I do not agree, they are software timers, but there is a is a scheduler that keeps track of ticks. I expect the task to consume CPU time when there is some kind of interaction with the task (either commands or a timer that expires); otherwise, why should it wake up?

In fact, the sources are documented as follows:

 * If a timer has expired, process it.  Otherwise, block the timer service task
 * until either a timer does expire or a command is received.
    static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime,                                            BaseType_t xListWasEmpty ) PRIVILEGED_FUNCTION;

Anyway the thing has been clarified.

Thank you again for your time.

Looking at the code for prvProcessTimerOrBlockTask(), I am hesitant to believe that it is truly blocking (there appear to be unresumed xTaskSuspendAll() scenarios in the control paths that may be blocking the task itself). But I am sure that the code is sound - it has been around for a long time. Whenever I can spare a few cycles, I’ll trace into it to see where my fallacy is.

Thanks, glad you got your issue resolved!

RAc, there is no need to “poll” for expired timers, because no timer can change its expiration time except by a message posted to the queue that is being waited on.

The code shown computes how long till the next timer will trigger, then waits no more than that long for an item to be put into the command queue. If an item is put on the queue, the queue is processed, and the it checks if any timers are expired, if so process them, then block on the queue again until the next one will run or another message arrives.

No CPU is used unless a message arrives or a timer expires. Using and event group in an ISR need to send a pend function message as that operation takes an unknown and variable amount of time, which seems to be the case here.

Just a minor update: I redesigned the application to use notifications in place of event groups, and I confirm that all the timer task wakeups (other than those related to actual timers) are gone.

Thank you sharing your finding!