Timers in FreeRTOS
Timers allow to execute functions at a set time in the future. The function executed by the timer is called the timer’s callback function. The time between a timer being started and its callback function being executed is called the timer’s period. Put simply, the timer’s callback function is executed when the timer’s period expires.
This section provides basic information and implementations for Timers
- Define Helpful Constants
- Create and Start a Timer
- xTimerCreate Parameters
- Timer Manipulation
- Full Code Example
- Appendix
Define Helpful Constants
Before we start with the implementation of a timer, it is particularly advantageous to define some helpful constants in order to get a clearer understanding of the function implementations.
/* constant definitions */
#define TIMERBLOCKTIME UINT32_C(0xffff)
#define TIMER_AUTORELOAD_ON pdTRUE
#define TIMER_AUTORELOAD_OFF pdFALSE
#define SECONDS(x) ((portTickType) (x * 1000) / portTICK_RATE_MS)
#define MILLISECONDS(x) ((portTickType) x / portTICK_RATE_MS)
Create and Start a Timer
First, we need to use the function xTimerCreate()
to create a new timer. This function returns a handle of type xTimerHandle
, through which the timer can be accessed. Afterwards, xTimerStart()
is called, using the handle for the timer that has been previously created.
#include "timers.h" // include the timer module
void createAndStartTimer(void)
{
xTimerHandle timerHandle = xTimerCreate(
(const char * const) "My Timer", // used only for debugging purposes
SECONDS(12), // timer period
TIMER_AUTORELOAD_ON, // Autoreload on or off - should the timer
// start again after it expired?
NULL, // optional identifier
myTimerCallback // static callback function
);
if(NULL == timerHandle) {
assert(pdFAIL);
return;
}
BaseType_t timerResult = xTimerStart(timerHandle, TIMERBLOCKTIME);
if(pdTRUE != timerResult) {
assert(pdFAIL);
}
}
xTimerCreate Parameters
The function xTimerCreate()
receives five parameters as input and returns either NULL
, if the timer could not be created, or an xTimerHandle
, through which the timer can be manipulated.
Details regarding the input parameters are listed in the table below.
Argument | Description |
---|---|
Name | A string constant that will be used as the name of the new timer. This name will only be used internally or for debugging purposes. Any string could be chosen. |
Period | The time interval after which the timer expires and the timer function is called. |
Auto Reload | A boolean (pdTRUE or pdFALSE ) that defines whether the timer should be automatically restarted after it expires. |
ID | This argument can be used to assign an arbitrary value to the new timer in order to identify it at a later point, for example in a callback function that handles multiple timers. |
Callback Function | A function that is called when the timer expires. This function has to be static, accept an xTimerHandle as its only parameter and return void. |
An example for the implementation of a callback is shown in the next code-snippet
#include "stdio.h" // for printf
static void myTimerCallback(xTimerHandle xTimer)
{
(void) xTimer;
printf("Timer fired!\r\n");
}
Timer Manipulation
FreeRTOS offers various functions to control and manipulate timers. They all expect a time interval as their last argument, that defines how long the calling task is held in blocked state while the system tries to perform the respective command.
xTimerHandle timerHandle = xTimerCreate(
(const char * const) "My Timer",
SECONDS(12), pdFALSE, NULL, myTimerCallback);
// change the timer period from 12 to 8 seconds
xTimerChangePeriod(timerHandle, SECONDS(8), MILLISECONDS(10));
// start counting from 0 again
xTimerReset(timerHandle, MILLISECONDS(10));
// stop the timer
xTimerStop(timerHandle, MILLISECONDS(10));
// delete the timer
xTimerDelete(timerHandle, MILLISECONDS(10));
The table below shows the effects on the timer of each function.
Function | Effect |
---|---|
xTimerStart() | The referenced timer starts counting up ticks until the chosen period expires. |
xTimerReset() | Resets the current count of the referenced timer, so that the timer has to count up again from zero. Behaves like xTimerStart, if period had been already reached. |
xTimerChangePeriod() | Changes the period of a timer. This will work even while the timer is counting ticks. |
xTimerStop() | Stops the referenced timer. As such, it will stop counting ticks. Also, the current tick-count will be set to zero. The timer can be later started again by using xTimerStart |
xTimerDelete() | Deletes the referenced timer. This can be called while the timer is running |
Notice that there are special versions of these functions to be used from within interrupt service routines (ISRs).
Full Code Example
Note: The full code example is intended for XDK-Workbench versions 3.4.0 and higher.
/* --------------------------------------------------------------------------- |
* INCLUDES & DEFINES ******************************************************** |
* -------------------------------------------------------------------------- */
/* own header files */
#include "XdkAppInfo.h"
#undef BCDS_MODULE_ID /* Module ID define before including Basics package*/
#define BCDS_MODULE_ID XDK_APP_MODULE_ID_APP_CONTROLLER
/* system header files */
#include <stdio.h>
/* additional interface header files */
#include "BCDS_CmdProcessor.h"
#include "FreeRTOS.h"
#include "timers.h"
/* --------------------------------------------------------------------------- |
* HANDLES ******************************************************************* |
* -------------------------------------------------------------------------- */
static CmdProcessor_T * AppCmdProcessor;/**< Handle to store the main Command processor handle to be used by run-time event driven threads */
/* --------------------------------------------------------------------------- |
* VARIABLES ***************************************************************** |
* -------------------------------------------------------------------------- */
#define TIMERBLOCKTIME UINT32_C(0xffff)
#define TIMER_AUTORELOAD_ON pdTRUE
#define TIMER_AUTORELOAD_OFF pdFALSE
#define SECONDS(x) ((portTickType) (x * 1000) / portTICK_RATE_MS)
#define MILLISECONDS(x) ((portTickType) x / portTICK_RATE_MS)
/* --------------------------------------------------------------------------- |
* EXECUTING FUNCTIONS ******************************************************* |
* -------------------------------------------------------------------------- */
static void myTimerCallback(xTimerHandle xTimer)
{
(void) xTimer;
printf("Timer fired!\r\n");
}
void createAndStartTimer(void)
{
xTimerHandle timerHandle = xTimerCreate(
(const char * const) "My Timer", // used only for debugging purposes
SECONDS(12), // timer period
TIMER_AUTORELOAD_ON, // Autoreload on or off - should the timer
// start again after it expired?
NULL, // optional identifier
myTimerCallback // static callback function
);
if(NULL == timerHandle) {
assert(pdFAIL);
return;
}
BaseType_t timerResult = xTimerStart(timerHandle, TIMERBLOCKTIME);
if(pdTRUE != timerResult) {
assert(pdFAIL);
}
}
/* --------------------------------------------------------------------------- |
* BOOTING- AND SETUP FUNCTIONS ********************************************** |
* -------------------------------------------------------------------------- */
static void AppControllerEnable(void * param1, uint32_t param2)
{
BCDS_UNUSED(param1);
BCDS_UNUSED(param2);
/* Enable necessary modules for the application and check their return values */
createAndStartTimer();
}
static void AppControllerSetup(void * param1, uint32_t param2)
{
BCDS_UNUSED(param1);
BCDS_UNUSED(param2);
Retcode_T retcode = RETCODE_OK;
/*Setup the necessary modules required for the application */
retcode = CmdProcessor_Enqueue(AppCmdProcessor, AppControllerEnable, NULL, UINT32_C(0));
if (RETCODE_OK != retcode)
{
printf("AppControllerSetup : Failed \r\n");
Retcode_RaiseError(retcode);
assert(0); /* To provide LED indication for the user */
}
}
void AppController_Init(void * cmdProcessorHandle, uint32_t param2)
{
BCDS_UNUSED(param2);
Retcode_T retcode = RETCODE_OK;
if (cmdProcessorHandle == NULL)
{
printf("AppController_Init : Command processor handle is NULL \r\n");
retcode = RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_NULL_POINTER);
}
else
{
AppCmdProcessor = (CmdProcessor_T *) cmdProcessorHandle;
retcode = CmdProcessor_Enqueue(AppCmdProcessor, AppControllerSetup, NULL, UINT32_C(0));
}
if (RETCODE_OK != retcode)
{
Retcode_RaiseError(retcode);
assert(0); /* To provide LED indication for the user */
}
}
/** ************************************************************************* */
Appendix
XDK Console Output example
The following console log is an example output of the code that has been implemented in the FreeRTOS Timers example guide: