FreeRTOS software timer

The software timer is an optional feature of FreeRTOS, implemented based on the system clock beat. Its implementation does not require the use of any hardware timer resources and is not limited in quantity, only system resource permissions are required.

Software timers allow specified functions to be executed after the set time has elapsed. This function that performs specified functions is called a software timer callback function. The time between the start of the software timer and the execution of the software timer callback function is called the software timer period. To put it simply, when the software timer’s timing time is up, the software timer callback function will be executed, and the function to be implemented is placed in the software timer callback function.

1 Software timer service task

Software timer is an optional feature of FreeRTOS. When configUSE_TIMERS is 1, a software timer service task (software timer daemon task) will be automatically created when the scheduler starts. The stack size and priority of the software timer service task are Level, command queue length, etc. must also be configured in the configuration file.
The API function that operates the software timer sends commands to the software timer service task through the queue. This queue is called the software timer command queue. The software timer command queue is private to the FrecRTOS software timer and cannot be accessed directly by users, but it is also the communication link between user tasks and software timer service tasks. The schematic diagram of the user task sending commands to the software timer service task through the software timer command queue is shown in the figure.

In the figure, the software timer command queue connects user tasks with software timer service tasks. The application in the user task sends the reset command to the software timer service task through the software timer command queue by calling the xTimerReset() function, but cannot call a queue operation function similar to xQueueSend() to send it.

2 Software timer operation

2.1 Single timing and periodic timing

FreeRTOS software timer supports single timing mode and periodic timing mode. Single timing mode means that after the user creates and starts the software timer, the software timer callback function will only be executed once when the timing time is reached, and then it will stop. Periodic timing mode means that the software timer will periodically execute the software timer callback function according to the set timing time until the software timer stop function is called.

Note: The software timer callback function is executed in the software timer service task. The software timer callback function
Never use API functions that cause task blocking, such as the vTaskDelay() function, etc.

2.2 Create software timer

Before using a software timer, you must first create a software timer. There are two functions for creating software timers: dynamic
Create function xTimerCreate() and static creation function xTimerCreateStatic().

2.2.1 xTimerCreate()

xTimerCreate() is used to dynamically create a software timer. The required memory is allocated through the dynamic memory allocation method.
Obtained, the software timer just created is in a dormant and not running state. The prototype of this function is as follows.

 TimerHandle_t xTimerCreate( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
const TickType_t xTimerPeriodInTicks,
const UBaseType_t uxAutoReload,
void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction )

Parameter Description:

pcTimerName: The name of the software timer for easy debugging.

xTimerPeriodInTicks: timing period, unit is system clock beat.

uxAutoReload: Software timer mode, pass in the pdTRUE parameter to create a periodic software timer, pass
Enter the pdFALSE parameter to create a one-shot software timer.

pvTimerID: Software timer ID, used to identify when multiple software timers use the same callback function
Which software timer caused the callback?

pxCallbackFunction: Software timer callback function.

Return value: The created software timer handle is returned if the creation is successful, and NULL is returned if the creation fails.

2.2.2 xTimerCreateStatic()

xTimerCreateStatic() is used to statically create a software timer. The required memory needs to be allocated by the user. The newly created software timer is in a dormant and not running state. Compared with the dynamic creation function, the static creation function has an additional pxTimerBuffer formal parameter, which is used to point to the software timer memory allocated by the user. The prototype of this function is as follows.

 TimerHandle_t xTimerCreateStatic( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
const TickType_t xTimerPeriodInTicks,
const UBaseType_t uxAutoReload,
void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction,
StaticTimer_t *pxTimerBuffer )

Parameter Description:

pcTimerName: The name of the software timer for easy debugging.

xTimerPeriodInTicks: timing period, unit is system clock beat.

uxAutoReload: Software timer mode, pass in the pdTRUE parameter to create a periodic software timer, pass
Enter the pdFALSE parameter to create a one-shot software timer.

pvTimerID: Software timer ID, used to identify when multiple software timers use the same callback function
Which software timer caused the callback?

pxCallbackFunction: Software timer callback function.

pxTimerBuffer: Points to a structure of type StaticTimer_t

Return value: The created software timer handle is returned if the creation is successful, and NULL is returned if the creation fails.

2.3 Start software timer

The newly created software timer is in the sleep state and is not running. There are two APIs that can be used to start the software timer: one is xTimerStart() for tasks; the other is xTimerStartFromISR() for interrupt service functions.

2.3.1 xTimerStart()

xTimerStart() is the software timer startup function. If the software timer is not running, calling this API can calculate the expiration time of the software timer and start the software timer; if the software timer is already running, calling this API is equivalent to resetting the software timer. This API is a macro, and the actual function is the xTimerGenericCommand() function. The macro is defined as follows.

#define xTimerStart( xTimer, xTicksToWait )
                    xTimerGenericCommand((xTimer),
                                 tmrCOMMAND_START,
                            (xTaskGetTickCount() ),
                                        NULL,
                                ( xTicksToWait ) )

Parameter Description:

xTimer: Handle of the software timer to be started.

xTicksToWait: Command queue blocking time, the software timer API sends commands to the software timer queue.

Return value: pdPASS is returned if the software timer is successfully started, and pdFAIL is returned if the software timer fails to be started.

2.3.2 xTimerStartFromISR()

xTimerStartFromISR() is the interrupt version of the API that starts the software timer and is used for interrupt service functions. this
The API is a macro, and the actual function is the xTimerGenericCommand() function. The macro is defined as follows.

#define xTimerStartFromISR( xTimer, pxHigherPriorityTaskWoken )
                xTimerGenericCommand((xTimer),
                    tmrCOMMAND_START_FROM_ISR,
                 (xTaskGetTickCountFromISR()),
                 (pxHigherPriorityTaskWoken),
                                0U )

Parameter Description:

xTimer: Handle of the software timer to be started.

pxHigherPriorityTaskWoken: Points to a variable used to save whether to perform task switching after calling the function. If the value is pdTRUE after executing the function, a task switching must be performed after exiting the interrupt service function.

Return value: pdPASS is returned if the software timer is successfully started, and pdFAIL is returned if the software timer fails to be started.

2.4 Stop software timer

Once the periodic software timer is started, it will run repeatedly until the software timer stop API is called. There are two APIs for stopping software timers: one is xTimerStop() for tasks; the other is xTimcrStopFromISR() for interrupt service functions.

2.4.1 xTimerStop()

xTimerStop() is used to stop the software timer. This API is a macro. The actual function is
xTimcrGcnericCommand() function. The macro is defined as follows.

#define xTimerStop( xTimer, xTicksToWait )
                xTimerGenericCommand((xTimer),
                                     tmrCOMMAND_STOP,
                                         0U,
                                        NULL,
                                 ( xTicksToWait ) )

Parameter Description:

xTimer: Handle of the software timer to be started.

xTicksToWait: Command queue blocking time, the software timer API sends commands to the software timer queue.

Return value: pdPASS is returned if the software timer is successfully stopped, and pdFAIL is returned if the software timer is stopped.

2.4.2 xTimcrStopFromISR()

xTimerStopFromISR() is the interrupt version of AIP that stops the software timer and is used for interrupt service functions. This API is a macro, and the actual function is the xTimerGenericCommand() function. The macro is defined as follows.

#define xTimerStopFromISR( xTimer, pxHigherPriorityTaskWoken )
                    xTimerGenericCommand((xTimer),
                                 tmrCOMMAND_STOP_FROM_ISR,
                                            0,
                         (pxHigherPriorityTaskWoken),
                            0U )

Parameter Description:

xTimer: Handle of the software timer to be started.

pxHigherPriorityTaskWoken: Points to a variable used to save whether to perform task switching after calling the function. If the value is pdTRUE after executing the function, a task switching must be performed after exiting the interrupt service function.

Return value: pdPASS is returned if the software timer is successfully stopped, and pdFAIL is returned if the software timer is stopped.

3 Software timer usage example

This example creates two software timers: one is a single-shot software timer with a period of 2000 system clock ticks (2s); the other is a periodic software timer with a period of 1000 system clock ticks (1s). Create two FrceRTOS tasks through the appStartTask() function.

The single software timer callback function is singleTimerCallBack(). Its function is to count the number of times the single software timer is used, send the information through the serial port, and change the on-off state of LED0 once.

The cycle software timer callback function is cycleTimerCallBack(). Its function is to count the number of cycle software timer time arrivals, send the information through the serial port, and at the same time change the on-off state of LED1 once.

Task 1 is a serial port daemon task with a priority of 3. The task function is printTask(). Its function is to pass the queue
The character information sent by the server is output on the serial port, and only the daemon task can access the serial port at any time.

Task 2 is a key scanning task with a priority of 4. The task function is keyTask(). Its function is to scan keys and start or stop the software timer based on the returned key value. The KEY1 button is used to start the single-shot software timer, the KEY2 button is used to start the periodic software timer, and the KEY3 button is used to stop the single-shot software timer and periodic software timer. Before starting the software timer, check the software timer first. Has it started running?

3.1 Configuring FreeRTOS

3.1.1 Include header files

#ifndef __APPTASK_H
#define __APPTASK_H

#include "FreeRTOS.h"
#include "semphr.h"
#include "task.h"
#include "queue.h"
#include "timer.h"


#include "key.h"



static void printTask(void *pvParameters);
static void keyTask(void *pvParameters);
void appStartTask(void);

#endif

3.1.2 Configuration macro

To use software timers, you need to configure the macro configUSE_TIMERS to 1. The macro configurations related to software timers are as follows.

/*Whether to use the software timer function: use 1*/
#define configUSE_TIMERS 1
/*Default priority of software timer service tasks*/
#define configTIMER_TASK_PRIORITY (2)
/*Software timer command queue length*/
#define configTIMER_QUEUE_LENGTH 10
/*Software timer service task stack size*/
#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2)

3.2 Software timer callback function

/********************************************** ************************
Function name: singleTimerCallBack
Function description: Single software timer callback function
Formal parameter: xTimer, used to mark the software timer that causes the callback function
Return value: None
*************************************************** ************************/
void singleTimerCallBack(TimerHandle_t xTimer)
{
static uint16_t cnt=0;
xTimer = xTimer;
\t
cnt + + ;
\t
GPIO_WriteBit(GPIOA,GPIO_Pin_4,(BitAction)(1 - GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_4))); //LED0 flashes
\t
sprintf(pcToPrint,"Single software timer, run = times\r\\
",cnt);
xQueueSendToBack(xQueuePrint,pcToPrint,0);
}
/****************************************************** *********************
Function name: cycleTimerCallBac
Function description: Single software timer callback function
Formal parameter: xTimer, used to mark the software timer that causes the callback function
Return value: None
*************************************************** ************************/
void cycleTimerCallBack(TimerHandle_t xTimer)
{
static uint16_t cnt=0;
xTimer = xTimer;
\t
cnt + + ;
\t
GPIO_WriteBit(GPIOA,GPIO_Pin_5,(BitAction)(1 - GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_4))); //LED0 flashes
\t
sprintf(pcToPrint,"Periodic software timer, run = times \r\\
",cnt);
xQueueSendToBack(xQueuePrint,pcToPrint,0);
}

3.3 Task function

/********************************************** ************************
Function name: printTask
Function description: The serial port daemon task uses a FreeRTOS queue to achieve serial access to the serial port. This daemon task is the only task that can directly access the serial port.
The serial port daemon task spends most of its time in the blocking state waiting for messages to arrive in the queue. When a message arrives,
The serial port daemon task simply sends the received message to the serial port, then returns to the blocking state and continues to wait for the arrival of the next message.
Formal parameters: pvParameters are the parameters passed when creating the task
Return value: None
Priority: 3
*************************************************** ************************/
void printTask(void *pvParameters)
{
char pcTowrite[80]; //Cache the data received from the queue
while(1)
{
/*When the queue is empty, that is, there are no characters to output, the blocking timeout is portMAX_DELAY, and the task will wait indefinitely.
Status, you can not detect the return value of the queue reading function*/
xQueueReceive(xQueuePrint,pcTowrite,portMAX_DELAY);
printf("%s",pcTowrite);
}
}
/****************************************************** *********************
Function name: keyTask
Function description: Key scanning task, perform corresponding operations according to the key value
Formal parameters: pvParameters are the parameters passed when creating the task
Return value: None
Priority: 4
*************************************************** ************************/
static void keyTask(void *pvParameters)
{
uint8_t keyValue = 0; //Storage key value
\t
while(1)
{
keyValue =Key_getNum();
if(keyValue == 1)
{
if(xTimerIsTimerActive(tmrSingleHandler) == pdFAIL)
{
sprintf(pcToPrint,"Start a one-shot software timer .........\r\\
\r\\
");
xQueueSendToBack(xQueuePrint,pcToPrint,0);
\t\t\t\t
xTimerStart(tmrSingleHandler,0);//Start the single software timer
}
else
{
\t\t
sprintf(pcToPrint,"One-shot software timer has started...\r\\
\r\\
");
xQueueSendToBack(xQueuePrint,pcToPrint,0);
\t\t\t
}
}
if(keyValue == 2)
{
if(xTimerIsTimerActive(tmrCycleHandler) == pdFAIL)
{
\t\t\t\t
sprintf(pcToPrint,"Start period software timer .........\r\\
\r\\
");
xQueueSendToBack(xQueuePrint,pcToPrint,0);
\t\t\t\t
xTimerStart(tmrCycleHandler,0);
}else
{
sprintf(pcToPrint,"Periodic software timer has started .........\r\\
\r\\
");
xQueueSendToBack(xQueuePrint,pcToPrint,0);
\t\t
}
}
else if(keyValue == 3)
{
sprintf(pcToPrint,"Stop all timers...\r\\
\r\\
");
xQueueSendToBack(xQueuePrint,pcToPrint,0);

xTimerStop(tmrSingleHandler,0);
xTimerStop(tmrCycleHandler,0);
\t\t
\t\t
}
vTaskDelay(pdMS_TO_TICKS(100));
}
}

3.4 Create software timers and tasks

static char pcToPrint[80]; //Buffer of content to be printed
xQueueHandle xQueuePrint; //Message queue handle

TimerHandle_t tmrSingleHandler; //Single timer handle
TimerHandle_t tmrCycleHandler; //Single timer handle

static TaskHandle_t printTaskHandle = NULL;//Task printTask task handle
static TaskHandle_t keyTaskHandle = NULL; //Key scanning task handle
/****************************************************** *********************
Function name: appStartTask
Function description: Task start function, used to create other functions and start the scheduler
Formal parameters: pvParameters are the parameters passed when creating the task
Return value: None
*************************************************** ************************/
void appStartTask(void)
{
\t
/*Create a queue with a length of 2 and a queue item large enough to accommodate the characters to be output*/
xQueuePrint = xQueueCreate(2,sizeof(pcToPrint));
/*Create 2 software timers, one single-shot software timer and one periodic software timer*/
\t\t
tmrSingleHandler = xTimerCreate("singleTimer",2000,pdFALSE,(void *)1,singleTimerCallBack);
tmrCycleHandler = xTimerCreate("cycleTimer",1000,pdTRUE,(void *)2,cycleTimerCallBack);
\t
\t
if(xQueuePrint & amp; & amp; tmrSingleHandler & amp; & amp; tmrCycleHandler)//If the queue semaphore is created successfully
{
\t\t\t\t
taskENTER_CRITICAL(); /*Enter critical section, turn off interrupts*/
\t

xTaskCreate(printTask,"printTask",128,NULL,3, & amp;printTaskHandle);
xTaskCreate(keyTask,"keyTask",128,NULL,4, & amp;keyTaskHandle);
taskEXIT_CRITICAL(); /*Exit the critical section and turn off interrupts*/
vTaskStartScheduler();/*Start the scheduler*/
}
\t\t
}

4 Download test

5 Summary

The FreeRTOS software timer has two working modes: single timing mode and periodic timing mode. The software timer must be created before use. The newly created software timer is in a dormant and not running state. Software timers can be operated through APIs such as start, reset, and stop. These APIs pass commands to software timer service tasks through the software timer command queue. The functions required by the software timer are implemented through the software timer callback function. API functions that will cause task blocking cannot be called in the software timer callback function.