In this blog post, we will be learning about Software Timer in FreeRTOS and use the software timer to send data to Serial Monitor every 1 second. We have learnt in previous that it is possible to use vTaskDelay() function to put a task into Blocked state for a specific time period. Instead of putting a task into Blocked state, we will learn how to schedule running a piece of code in a specific interval using timer.
freeRTOS software timer
We will first need to learn a few concepts before we start using software timer. Firstly, we’ll talk briefly about software timer callback function. The callback function is executed when the timer expires. The function prototype looks like void ATimerCallback(TimerHandle_t xTimer). We are familiar with the way of using a handle to refer to an entity, here is a timer handle. It is expected that this handle is the value returned when creating a timer, which we will see soon. The callback function may be called once only or repeatedly depending on the type of the timers. For single shot timer, the callback function is called once only when the timer expires. For auto-reload timer, the callback function is called again and again each time timer expires until timer is stopped by calling xTimerStop().
A software timer can exist in one of the states: dormant or running. If a timer is created, but not running, it is in dormant state. Otherwise, the timer runs and counts, when it expires, the callback function is executed. Note that a timer counts in the number of kernel ticks. Beside two available states of a software timer, it is also important to know the context in which a software timer runs. The software timer runs in a task called daemon task. The daemon task is a task that is created automatically when the scheduler starts. It is similar to any other application tasks which means it has its own stack and has a priority. When the daemon task run depends on its priority which is defined by the parameter configTIMER_TASK_PRIORITY. The daemon task and application task communicate with each other via a queue. When an application task calls a software timer API function, for example xTimerStart(), the application task is writing to a timer command queue. When the daemon task takes turn to run, it reads the queue and processes the command.
Software timer APIs
Create a timer
As expected, to use a software timer, it must be first created. So we can expect a xTimerCreate function which returns the handle of the timer that we can refer to. What are parameters that we need to pass in the function xTimerCreate to initialise a timer? We’ll need at least the following parameters if we follow the discussion above: the number of ticks that specifies the timer period, the type of the timer (single shot or auto-reload) and a callback function. Actually, we still need to pass in two more argument as shown below:
The pcTimerName is a descriptive name for debugging purposes and should be a readable name. The pvTimerID is a timer ID value. The xTimerCreate function returns NULL if the timer can not be created and return the handle of the timer if it is created successfully.
In our example, we want to create a timer that has period of 1 second, and in the callback function, we will send data to the Serial Monitor. To create the timer, we can use xTimerCreate as follow:
Start a timer
To start a timer, xTimerStart() function is used. The xTimerStart() function takes two arguments. The first argument is the handle of the timer to start, the second argument is xTicksToWait which specifies how long the calling task should be placed in Blocked state to wait if the timer command queue is already full. To start our timer1, we can call xTimerStart(timer1, 0). xTimerStart() returns pdPASS if timer can run or pdFAIL if timer can not be started due to timer command queue is already full.
For our example, we will be using only two API functions: xTimerCreate and xTimerStart to implement the functionality that sending data to Serial Monitor every 1 second. All we need to do is to initialise the timer to interrupt every 1 second and in the timer callback function, we send data to the Serial Monitor. Code is shown below
Compile and upload this code with Arduino IDE and open Serial Monitor, you will see the following output:
Other API functions
Other than xTimerCreate and xTimerStart, there are other API functions
- xTimerStop() to stop a timer
- xTimerReset() to reset a timer
- xTimerChangePeriod() to change the period of a timer
Once you understand the basic principal of software timer above, using these API function is relatively easy. It can be adopted to different projects in need. We’ll probably use those functions in other posts as well.
That’s it for today’s post. We’ll continue to learn other FreeRTOS concepts and projects in the coming posts.