FreeRTOS_Software timer (Timer)

Directory title

  • 1. Software timer characteristics
  • 2. Guarding tasks
  • 3. Software timer API
    • 3.1. Create software timer
    • 3.2. Callback function
    • 3.3. Delete timer
    • 3.4. Start/stop timer
    • 3.5. Modify the timer period
    • 3.6. Reset timer (Reset)
    • 3.7. Timer ID

1. Software timer features

Using a timer requires configuring timer period, callback function, and type (one-time, automatic loading).
The timer has two states: Running and Hibernation.

2. Guardian mission

The software timer daemon task is a background task responsible for managing and processing software timers. Daemon tasks usually run in the operating system’s scheduler and are responsible for the following main functions:

  • Creating and deleting timers: Daemon tasks can receive requests from other tasks or users and create new timers or delete existing timers based on these requests.
  • Calling the timer callback function: The daemon task will call the corresponding timer callback function according to the set time of each timer. The timer callback function is a piece of code that is automatically triggered when the timer expires and is used to perform the corresponding task or operation.
  • Periodic scheduling of timers: The daemon task is responsible for executing the timer callback function on time according to the set time and requirements of the timer. It determines when to trigger the timer based on the timer’s period or delay.
  • Pause and resume of timers: Daemon tasks can control the pause and resume of timers to achieve dynamic management of timers. This allows you to pause the firing of timers as needed and then resume them when appropriate.

Queues are used to communicate between software timers and daemon tasks. The use of queues can decouple timers and daemon tasks, improving the scalability and flexibility of the system. Daemon tasks can dynamically schedule and manage timers based on messages in the queue, while timer tasks only need to be responsible for triggering timers on time and sending corresponding messages to the queue, without caring about specific processing logic.

3. Software timer API

3.1. Create software timer

There are two ways to create a software timer: dynamically allocating memory and statically allocating memory.

//Dynamically allocate memory:
TimerHandle_t xTimerCreate(
const char * const pcTimerName,
const TickType_t xTimerPeriodInTicks,
const UBaseType_t uxAutoReload,
void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction );
//Static allocate memory:
TimerHandle_t xTimerCreateStatic(
const char * const pcTimerName,
TickType_t xTimerPeriodInTicks,
UBaseType_t uxAutoReload,
void *pvTimerID,
TimerCallbackFunction_t pxCallbackFunction,
StaticTimer_t *pxTimerBuffer );
Parameter Description
pcTimerName Timer name, used for debugging and logging.
xTimerPeriodInTicks Timeout event, timer period, in units of clock ticks (Tick)
uxAutoReload mode, pdTRUE: automatically load pdFALSE: one-time
pvTimerID The callback function can use this parameter to determine Which timer has timed out
pxCallbackFunction Callback function
pxTimerBuffer Execute the StaticTimer_t structure, used to store the timer structure
Return value A TimerHandle_t type value, representing the handle of the successfully created timer .

Note: When using the created software timer function in your own transplanted version of the library function, you need to add the following macro definitions to FreeRTOSConfig.h:

#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY (2)
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH 256

Otherwise, the following error will be reported:

.\Objects\2.axf: Error: L6218E: Undefined symbol xTimerCreate (referred from main.o).
Not enough information to list image symbols.

3.2. Callback function

When creating a software timer, you need to specify a callback function. FreeRTOS automatically calls this function when the timer expires.

typedef void (* TimerCallbackFunction_t)( TimerHandle_t xTimer );
void ATimerCallback(TimerHandle_t xTimer);
Parameter Description
xTimer Timer handle

Note: The callback function must be executed as soon as possible and cannot enter the blocking state

Example:

void vTimerCallback(TimerHandle_t pxTimer) {<!-- -->
    if (pxTimer == xTimer1) {<!-- -->
        // Processing logic for Timer1 expiration
    } else if (pxTimer == xTimer2) {<!-- -->
        // Timer2 expiration processing logic
    } else {<!-- -->
        // Processing logic for other timer expirations
    }
}
TimerHandle_t xTimer1, xTimer2;

//Create Timer1 and specify the callback function as vTimerCallback
xTimer1 = xTimerCreate("Timer1", pdMS_TO_TICKS(1000), pdTRUE, 0, vTimerCallback);

//Create Timer2 and specify the callback function as vTimerCallback
xTimer2 = xTimerCreate("Timer2", pdMS_TO_TICKS(2000), pdTRUE, 0, vTimerCallback);

3.3. Delete timer

A timer that dynamically allocates memory and can be deleted to reclaim memory when we don’t need it.

BaseType_t xTimerDelete(
TimerHandle_t xTimer,
TickType_t xTicksToWait );
Parameter Description
xTimer Timer handle
xTicksToWait Timeout time
Return value pdPASS: Success pdFAIL: The queue for communication with the daemon task is full and cannot be written

3.4. Start/stop timer

  • Start timer
/*Used in tasks*/
BaseType_t xTimerStart(
TimerHandle_t xTimer,
TickType_t xTicksToWait );
/*Used in ISR*/
BaseType_t xTimerStartFromISR(
TimerHandle_t xTimer,
BaseType_t *pxHigherPriorityTaskWoken );
Parameter Description
xTimer Software timer handle
xTicksToWait Blocking wait timeout
pxHigherPriorityTaskWoken Issue a command to the queue to wake up the guardian task. If the priority of the guardian task is higher than the current task, then “*pxHigherPriorityTaskWoken = pdTRUE”, indicating that task scheduling is required
Return value pdPASS: Success pdFAIL: Failure (unable to write to the daemon task queue within the specified time)
  • Stop timer
/*Used in tasks*/
BaseType_t xTimerStop(
TimerHandle_t xTimer,
TickType_t xTicksToWait );
/*Used in ISR*/
BaseType_t xTimerStopFromISR(
TimerHandle_t xTimer,
BaseType_t *pxHigherPriorityTaskWoken );
Parameter Description
xTimer Software timer handle
xTicksToWait Blocking wait timeout
pxHigherPriorityTaskWoken Issue a command to the queue to wake up the guardian task. If the priority of the guardian task is higher than the current task, then “*pxHigherPriorityTaskWoken = pdTRUE”, indicating that task scheduling is required
Return value pdPASS: Success pdFAIL: Failure (the stop command cannot be written to the daemon task queue within the specified time)

3.5. Modify the timer period

If the modified timer is in sleep state at this time, using this function will wake it up. And using the xTimerChangePeriod() function will re-accumulate the timeout time from when this function is called.

/*Used in tasks*/
BaseType_t xTimerChangePeriod(
TimerHandle_t xTimer,
TickType_t xNewPeriod,
TickType_t xTicksToWait );
/*Used in ISR*/'
BaseType_t xTimerChangePeriodFromISR(
TimerHandle_t xTimer,
TickType_t xNewPeriod,
BaseType_t *pxHigherPriorityTaskWoken );
Parameter Description
xTimer Software timer handle
xNewPeriod New period
xTicksToWait The blocking waiting timeout of the command writing queue
pxHigherPriorityTaskWoken Issuing a command to the queue causes the guardian task to be awakened. If the priority of the guardian task is higher than the current If the task is high, then “*pxHigherPriorityTaskWoken = pdTRUE” means task scheduling is required
Return value pdPASS: Success pdFAIL: Failure (unable Write the reset command to the daemon task queue within the specified time)

3.6. Reset timer (Reset)

  • Using the xTimerReset() function can convert the timer state from hibernation to running state, which is equivalent to using the xTimerStart() function.
  • Using the xTimerReset() function will re-accumulate the timer’s timeout from the time this function is called.
/*Used in tasks*/
BaseType_t xTimerReset(
TimerHandle_t xTimer,
TickType_t xTicksToWait );
/*Used in ISR*/
BaseType_t xTimerResetFromISR(
TimerHandle_t xTimer,
BaseType_t *pxHigherPriorityTaskWoken );
Parameter Description
xTimer Software timer handle
xTicksToWait The blocking wait timeout of the command write queue
pxHigherPriorityTaskWoken Issue a command to the queue to wake up the guardian task. If the priority of the guardian task is higher than the current task, then”*pxHigherPriorityTaskWoken = pdTRUE” means that task scheduling is required
Return value pdPASS: Success pdFAIL: Failure (unable to write the reset command to the daemon task queue within the specified time)

3.7, timer ID

  • Get timer ID
void *pvTimerGetTimerID(
TimerHandle_t xTimer );
Parameter Description
xTimer Software timer handle
Return value A void* type pointer pointing to the timer identifier
  • Update timer ID
void vTimerSetTimerID(
TimerHandle_t xTimer,
void *pvNewID );
Parameter Description
xTimer Software timer handle
pvNewID New timer ID
Return value None

Example:

#define TIMER_PERIOD_MS (1000) // Timer period
#define SWITCH_COUNT (5) // Number of times the switch identifier is sent

typedef struct {<!-- -->
    uint32_t send_count; // Number of times sent
    bool is_first_callback; // Whether it is the first callback
} timer_data_t;

// timer callback function
void timer_callback(TimerHandle_t xTimer){<!-- -->
    timer_data_t *pData = (timer_data_t*)pvTimerGetTimerID(xTimer); // Get the identifier
    
    // send data
    send_data();
    
    //Update the number of sending times and determine whether the identifier needs to be switched
    pData->send_count + + ;
    if(pData->send_count == SWITCH_COUNT){<!-- -->
        void *pNewID;
        if(pData->is_first_callback){<!-- -->
            pNewID = NULL; //The first callback does not have an identifier
        }else{<!-- -->
            pNewID = & amp;pData->send_count; // The second callback with identifier
        }
        vTimerSetTimerID(xTimer, pNewID); // Switch identifier
        pData->is_first_callback = false;
    }
}

void main(){<!-- -->
    TimerHandle_t xTimer;
    timer_data_t timer_data = {<!-- -->0};
    void *pInitialID = & amp;timer_data.send_count;
    
    xTimer = xTimerCreate("timer", TIMER_PERIOD_MS / portTICK_PERIOD_MS,
                          pdTRUE, pInitialID, timer_callback); // Create timer
    xTimerStart(xTimer, 0); // Start the timer
    
    while(1){<!-- -->
        //Other task processing
    }
}