Reference, RTOS, Technical
comments 11

The FreeRTOS Tick – Unravel the Mystery to Master the Tick

Over the last few years, I have become a fan of FreeRTOS for a few different reasons:

  1. It’s free (though a paid versions allow for some protection)
  2. Portable as it abstracts well from the hardware it runs on
  3. Provides an easy way to separate sections of code
  4. Allows for control of when, and how often, tasks are run

It’s the last point that this post will delve into. How does each thread (tasks in FreeRTOS speak) control when they run? It all comes down to the ‘tick,’ the magical trigger that FreeRTOS uses to know when to switch which task is running or give up waiting for a semaphore that will never be given.

Looking at FreeRTOS and its system Tick

What Drives the FreeRTOS Tick

It all comes from the FreeRTOS Tick – the function that is called at a periodic interval. As we will see below, this tick drives the context switch between tasks. But first, what drives this tick?

At the simplest level, the tick is just a timer that has a period set to match the desired tick rate. By default, this is set to 1ms which provides a good balance between task speed and overhead of task switching. The timer interrupt is triggered every time the period is hit. The ISR calls into FreeRTOS’ vTaskSwitchContext() function which we dive into below.

For ARM core processors, there is a special timer designed specifically for the purpose of providing an RTOS its tick. This timer is called the SysTick (System Tick) and provides its own clock configuration, counter value, and interrupt flag. This allows you to set up the SysTick to provide FreeRTOS’ tick and use all the other timers for your program’s needs.

But as we will look at in future posts, we can utilize the flexible nature of what drives the FreeRTOS tick to reduce power.

What Happens at the FreeRTOS Tick

So coming back to the vTaskSwitchContext() function that is called during the timer tick, what happens when the tick happens?

While we won’t focus on the nature of cooperative and preemptive multitasking. You can check out the links provided to get a review of these multitasking models. FreeRTOS allows for both models, but our discussion on the tick makes more sense in the preemptive mode.

In FreeRTOS, you create ‘tasks’ that contain a functional component that you want to run at specific times or in reaction to other events.  When the operation system is running, each of these tasks exists in one of four states:

  • Running – the process currently doing work
  • Ready – is available to run as soon as the OS allows it
  • Blocked – waiting for an event to allow it to run
  • Suspended – not even checked by the OS, task is shut off

When the tick triggers vTaskSwitchContext() the kernel looks at which tasks are in the Ready state and if there are any higher priority tasks than the current one, it switches context to allow the task time to run.

The diagram below shows a basic example of three tasks switching context either due to priority interrupt or context switching during the tick.

FreeRTOS Tick switching tasks

Key: P = Preemption, S = Switch, * = task has gone into blocked state

Higher priority tasks (higher number in FreeRTOS) are immediately switched to if they become unblocked due to a semaphore or queue releasing them and the next task takes over if any task goes into the blocked state (waiting for a semaphore or queue).

Tick Drives Round Robin

The FreeRTOS tick also looks for any other tasks that are equal in priority and will give each a chance to run. If multiple tasks are the same priority and are always in the Running or Ready state, the kernel creates a Round Robin model where each gets a full tick before switching to the next.

This Round Robin mode is where the balance between how fast the System Tick should be. A faster tick would allow more tasks to do operations in a given timeframe, but each task will only be able to do a limited amount of work before having to stop. And while the kernel is small and optimized for microcontrollers, it still takes a certain amount of time for it to save the current task’s context and load in the next task.

Ticks can Unblock Tasks

While the FreeRTOS tick function generally is switching context between equal priority tasks, it could also cause tasks to go from the Blocked to the Ready state, potentially moving a higher priority task into the Running state. One way this happens is if a task has called vTaskDelay() which delays a certain number of ticks.

Each call to vTaskSwitchContext() checks if any task is blocked due to the delay function and update’s its state if it has elapsed the desired time.

What if Nothing Needs to Happen

For many systems, especially low power systems, you don’t want tasks constantly running. In part, this happens because tasks are generally setup to react to certain events, events that may not happen often.

Between waiting for the next event, it could be that all of your tasks have nothing to do and have entered the Blocked state.

The Idle Task of Last Resort

When this occurs, FreeRTOS’ idle task runs instead, which is where FreeRTOS does some garbage collection for systems that create and delete tasks during runtime. Otherwise, the idle task is where you do low priority tasks like diagnostics or logging. This code could be called by the idleTaskHook function inside the Idle task, or creating tasks that are set to the idle priority of 0.

Looking at Lower Power

What we will get into later is looking at how long we need to wait for the next task to be serviced or times out waiting. We can use this information to decide to go into lower power states to conserve battery life or improve power efficiency.

At the simplest level, the ARM call to WFI will put the processor on hold until the next interrupt kicks it back into gear. This saves a small amount of current as the core processor clock is disabled until the next FreRTOS tick.

Shortly we will have a post focused strictly on the low power aspect of FreeRTOS. If you want to make sure you notified of these upcoming posts, sign up for our weekly newsletter below.

  • Pattern-chaser

    System ticks, and software timers, are usually and unjustifiably ignored. Thanks for turning your spotlight on them, Joe. I think it’s assumed that timers/task-timing are so simple they’re self-evident, but I don’t think they are. The details of how your application (or RTOS) handles timers can have a significant affect on your application, and how well it runs. And the choice of how you multi-task (co-operative or pre-emptive) has a huge effect on how your tasks co-operate (or don’t).

    Keep up the good work!

    • Thanks!
      I agree that timers are often overlooked and silicon vendors will often make them overly complicated for something as simple as a clock timer. I was recently trying to get a STM32L0 to just give me an 10us delay (rather than doing a blocking while loop) and still haven’t been able to get it to trigger the interrupt!

  • Luca

    Nice article, but I’m struggling to understand what happens between ticks.
    I mean, the scheduler runs on every periodic tick interrupt, performing scheduling work…but what if a task blocks before a tick? the documentation says that the context is immediately switched to the highest priority task in the ready state. So how does this happen?

    • Hey Luca, thanks for stopping by.
      So the first one, if a tasks blocks before a tick it returns back to the scheduler and it can start the next task. If nothing is set to run it will idles until something happens or go to sleep. The idle depends on the architecture and in the Cortex case that I know of, it does a WFI (wait for interrupt) that lowers the core power a bit but will immediately start again on the next interrupt (like the clock tick).
      In the case where a higher priority task becomes unblocked through releasing a Mutex or an ISR pushing to a queue for example, they call into vPortYield which is, again, architecture specific. On the Cortex this function sets the interrupt flag portNVIC_PENDSVSET and allows the schedule to do a context switch.
      Hope that helps! I had to dig back through the code myself to remember

      • Luca

        So if I get it right:
        A task can call vTaskDelay() and it blocks until the specified number of ticks occur. By doing so, the delay function calls portYied and sets a pending SV call interrupt (I’m on CortexM) which calls the scheduler right? The scheduler itself runs only in a ISR?
        If a task is unblocked by a synch event, the task (or ISR) possibly unblocking it is in charge of checking and if so calling portYield and trigger a context switch?
        Thanks for your reply!

  • Dinesh Kumar

    Excellent article on FreeRTOS ticks . i m beginner of rtos i want more article about
    Queue,Semaphores,MUTEXES, like this..

    • Pattern-chaser

      Hi Dinesh, If I have understood you correctly, I think you need more than an article. Using an RTOS, and all the facilities they offer, might be a bit too large a scale for an article. Are you trying to avoid a three-year university course, hoping ofr a magic article that will teach you all you need to know? Please don’t take this as discouragement! You are trying to learn, and that is the first step. But, as you progress in our software industry, you will hear the phrase “there’s no silver bullet”, and it’s true here as it is everywhere. There are no short-cuts to becoming a software developer. It takes years and lots of hard work. But you have started; keep up the good work! 🙂

      • Thanks for your reply as well. I agree that RTOS is a huge topic, and articles like this help with only a part of it. It does take years of practice to really ‘get it’ but I can appreciate the struggle to get started when trying to learn an RTOS without much background. Finding a few articles to get the gist, and then dive in to try it.

    • Thanks Dinesh. I had a ton more planned but life and work priorities put a halt to much of it. The manual from FreeRTOS will get you a good step forward, but to Pattern-chaser’s point, you should just start working with the platform and try things. I ended up re-do many parts of my code as I figured out better ways to use each piece.

      • Pattern-chaser

        Yes, Dinesh, start with the manual. If you have difficulty with it, you may need to do some background learning on the areas causing you problems. Read books, articles and blog posts by working designers like Joe, and also from gurus like Cope (James O Coplien), ‘Uncle’ Bob Martin, Michael Feathers, Martin Fowler, and so on. Learn anywhere you can, from anyone you can. But also do as Joe recommended and try things out. Ignore those who tell you to stop thinking (and reading, etc) and start doing! Instead you should carry on with all that thinking, and start doing as well. The two feed off each other, and you will progress the fastest when you use them both, in balance. All IMO, of course. 😉

        [Shameless plug: I have written some blog posts on various aspects of designing firmware. Here is the one about RTOSs. It’s more general than Joe’s post, and more about why you should use them than how. There are other posts there too. I hope you find something useful there.]

  • Liqiang Du

    Nice article, one question here is that the RTOS tick is sourced from SysTick for ARM, can it be changed to some low power timers instead? Thanks!