Date: abril 3, 2025
Author: Guillermo Garcia
Categories: RTOS Tags: FreeRTOS
Timers in FreeRTOS its essential features is the software timer, which allows tasks to be executed at specific intervals without consuming CPU resources in a busy loop. In this article, we will explore software timers in FreeRTOS, their functionality.
Table of Contents
A software timer in FreeRTOS is a timer managed by the FreeRTOS kernel rather than a hardware peripheral. The time between the start of the timer and the execution of its callback function is called the timer period. A timer callback function is executed when the timer period expires.
There are two types of Timer in FreeRTOS:
One-shot timers: Once started, a single-use timer will execute its callback function only once. It can be reset manually, but it will not reset automatically.
auto-reload timers: An auto-reload timer will automatically reset after each execution of its callback function, resulting in periodic execution of the callback.
Getting started with Timers in FreeRTOS is very simple. There are a number of APIs to manipulate Timers in a FreeRTOS-based application as shown below.
To create a Timer we use the xTimerCreate
function where we must specify some parameters. Let’s quickly see what we should pay attention to.
TimerHandle_t xTimerCreate( const char * const pcTimerName, const TickType_t xTimerPeriod, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction );
pcTimerName: Represents a string representing the identifier name for the Timer.
xTimerPeriod: Represents the time we want to set for the Timer.
uxAutoReload: Defines the behavior of the Timer
pdFALSE
): Triggers once and stops.pdTRUE
): Continuously triggers at regular intervals.pvTimerID: It is an identifier to distinguish between Timers in the application.
pxCallbackFunction: Represents a callback function when the Timer expires this function is created by the application.
Once a Timer is closed and started, it can be manipulated at Runtime as needed by the application. To start the Timer, we use the following API.
BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xBlockTime );
If you want to stop the Timer you can do so using the following API.
BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xBlockTime );
Timers in FreeRTOS are managed by the kernel itself, for this it assigns certain resources so that the timers are available, so we must indicate when we want to use the timers to FreeRTOS, for this it is necessary to add some definitions in FreeRTOSConfig.h.
/* Software timer definitions. */ #define configUSE_TIMERS 1 #define configTIMER_TASK_PRIORITY ( 2 ) #define configTIMER_QUEUE_LENGTH 10 #define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 )
The timers are managed by a Task created by the FreeRTOS Kernel itself, so it is necessary to indicate whether we want to use the Timers or simply do not need them and thus avoid unnecessary resources in the system, to enable the timers #define configUSE_TIMERS 1
should be set to 1.
Let’s go to our STM32F407VG Discovery kit board and create a program where we will use a timer that changes the time period each time we press the button on the board.
#include "Timer.h" TimerHandle_t xTimer; SemaphoreHandle_t xSemaphore; uint32_t TimePeriodic[] = {500, 600, 700, 800, 900}; size_t index = 0; void vTimerCallback(TimerHandle_t xTimer) { SEGGER_SYSVIEW_PrintfHost("Timer Timeout: %u\n", xTimerGetPeriod(xTimer)); } void TaskTimerChange(void* NotUsed) { /* Start the timer periodic */ xTimerStart(xTimer, 0); while(1) { /* Use the semaphore to wait for the event. The task blocks indefinitely meaning this function call will only return once the semaphore has been successfully obtained - so there is no need to check the returned value. */ SEGGER_SYSVIEW_Print( "Take xSemaphore\n" ); xSemaphoreTake(xSemaphore, portMAX_DELAY); /* changes the period of a timer that was previously created */ xTimerChangePeriod(xTimer, TimePeriodic[index++] / portTICK_PERIOD_MS, 100); index %= sizeof(TimePeriodic)/sizeof(TimePeriodic[0]); } } void Software_timer(void) { /* Create a software timer */ xTimer = xTimerCreate("MyTimer", pdMS_TO_TICKS(TimePeriodic[index]), pdTRUE, (void *)0, vTimerCallback); /* Create Semaphore */ xSemaphore = xSemaphoreCreateBinary(); /* Create tasks */ xTaskCreate(TaskTimerChange,"Tarea 1",configMINIMAL_STACK_SIZE, NULL,tskIDLE_PRIORITY+2,NULL); } void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { static BaseType_t xHigherPriorityTaskWoken; SEGGER_SYSVIEW_RecordEnterISR(); /* This is Button ISR */ if(GPIO_Pin==B1_Pin) { /* 'Give' the semaphore to unblock the task.*/ SEGGER_SYSVIEW_Print( "Give xSemaphore\n" ); xSemaphoreGiveFromISR(xSemaphore, &xHigherPriorityTaskWoken); /* Giving the semaphore may have unblocked a task - if it did and the unblocked task has a priority equal to or above the currently executing task then xHigherPriorityTaskWoken will have been set to pdTRUE and portEND_SWITCHING_ISR() will force a context switch to the newly unblocked higher priority task. */ portEND_SWITCHING_ISR( xHigherPriorityTaskWoken ); } SEGGER_SYSVIEW_RecordExitISR(); } int main() { HAL_SYSTICK_Config(SystemCoreClock / (1000U / (uint32_t)uwTickFreq)); HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0U); HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); traceSTART(); Software_timer(); vTaskStartScheduler(); }
El timer funciona cada 500 ms de manera periodica una vez que se inicia la tarea de control esta esperando que se presione el Boton para cambiar el periodo de el Timer. Aqui podemos ver que la funcion de callback void vTimerCallback(TimerHandle_t xTimer)
se llama desde una Tarea llamada Tmr Svc que es una tarea creada para asignar recursos y administrar los Timers.
Presionamos el boton y cambiamos el periodo de nuestro Timer.
El periodo del timer cambia a 600 ms.
FreeRTOS software timers provide a powerful way to schedule tasks without relying on hardware timers. By understanding how to create, start, stop, and reset these timers, you can enhance your embedded applications with efficient event-driven behavior.
Deja una respuesta