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

  1. Define Helpful Constants
  2. Create and Start a Timer
  3. xTimerCreate Parameters
  4. Timer Manipulation
  5. Full Code Example
  6. Appendix
    1. XDK Console Output example

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.

ArgumentDescription
NameA 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.
PeriodThe time interval after which the timer expires and the timer function is called.
Auto ReloadA boolean (pdTRUE or pdFALSE) that defines whether the timer should be automatically restarted after it expires.
IDThis 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 FunctionA 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.

FunctionEffect
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:

fig1