[getting started with FreeRTOS] FreeRTOS task management

Posted by nikifi on Mon, 10 Jan 2022 07:52:58 +0100

FreeRTOS task creation and suspension

1 task related concepts

Task status

  • Running state
    When a task is running, it can be said that the task is running. If it is a single core processor, there is always only one task in progress at any time.

  • Ready
    Tasks in the ready state are those that are ready (these tasks are not blocked or suspended) and can be run, but the tasks in the ready state have not been run because there is a higher priority task running.

  • Blocking state
    When a task is waiting for an external event, it indicates that it is in the blocking state. For example, calling the function vtask delay() will enter the blocking state until the delay cycle is completed. There is a timeout in the blocking state. After that, it will exit the blocking state.

  • Suspended state
    After the task is suspended, it cannot enter the running state again, but there is no timeout. Call the functions vtask suspend() and xtask resume()

Task priority

  • Preemptive scheduling: when a new task is ready and the priority is greater than or equal to the priority of the current task, the current task will be preempted; You need to configure yourself_ Preemption configuration.
  • Each task can be assigned a 0 ~ configmax_ The priority of priorities-1 (defined in freertosconfig. H), and the macro definition cannot exceed 32
  • The highest priority task in ready status will run.
  • When configure_ TIME_ When slicing is defined as 1, multiple tasks can share a priority, which is in FreeRTOS by default H has been defined as 1

Task function

Use xtask create() to create a task

Official task function template

void vATaskFunction(void *pvParameters)
{
    for(;;)
    {
        //Task application
        vTaskDeley();
    }
    vTaskDelete(NULL);
}

If you want to jump out of the loop end task, add vtask delete (null);

Task control block

In tasks Defined in C

typedef struct tskTaskControlBlock
{
	volatile StackType_t *pxTopOfStack; //Top of task stack
	#if ( portUSING_MPU_WRAPPERS == 1 )
		xMPU_SETTINGS	xMPUSettings;//mpu related settings
	#endif

	ListItem_t     xStateListItem;	//Status list item
	ListItem_t     xEventListItem;	//Event list item
	UBaseType_t     uxPriority;	//Task priorities
	StackType_t     *pxStack;		//Start address of task stack
	char     pcTaskName[ configMAX_TASK_NAME_LEN ]; //Task name

	#if ( portSTACK_GROWTH > 0 )
		StackType_t     *pxEndOfStack;	//Task stack bottom
	#endif

	#if ( portCRITICAL_NESTING_IN_TCB == 1 )
		UBaseType_t     uxCriticalNesting;	 //Nesting depth of critical area

	#If (configure_trace_facility = = 1) / / used in trace or debug
		UBaseType_t     uxTCBNumber;		/*< Stores a number that increments each time a TCB is created.  It allows debuggers to determine when a task has been deleted and then recreated. */
		UBaseType_t     uxTaskNumber;		/*< Stores a number specifically for use by third party trace code. */
	#endif

	#if ( configUSE_MUTEXES == 1 ) 
		UBaseType_t		uxBasePriority; //The basic priority of the task is used when the priority is reversed
		UBaseType_t		uxMutexesHeld; //The number of mutually exclusive semaphores obtained by the task
	#endif

	#if ( configUSE_APPLICATION_TASK_TAG == 1 )
		TaskHookFunction_t pxTaskTag;
	#endif

	#If (confignum_thread_local_storage_points > 0) / / related to local storage
		void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
	#endif

	#if( configGENERATE_RUN_TIME_STATS == 1 )
		uint32_t		ulRunTimeCounter; //It is used to record the total running time of the task
	#endif

	#if ( configUSE_NEWLIB_REENTRANT == 1 )

		struct	_reent xNewLib_reent; //A newlib struct variable is used to create a new struct
	#endif

	#If (configure_task_notifications = = 1) / / task notification related variables
		volatile uint32_t ulNotifiedValue; 
		volatile uint8_t ucNotifyState;
	#endif

	/* See the comments above the definition of
	tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */
	#If (tskstatic_and_dynamic_allocation_possible! = 0) / / used to mark whether it is created dynamically or statically
		uint8_t	ucStaticallyAllocated; 		/*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */
	#endif

	#if( INCLUDE_xTaskAbortDelay == 1 )
		uint8_t ucDelayAborted;
	#endif

} tskTCB;

/* The old tskTCB name is maintained above then typedefed to the new TCB_t name
below to enable the use of older kernel aware debuggers. */
typedef tskTCB TCB_t;

task stack

If you create a task with xTaskCreate(), it will be created dynamically and the stack will be allocated automatically. If you create a task with xTaskCreateStatic(), it will be created statically. The programmer needs to define the task stack and pass the first address of the stack to the function as a parameter puxsackbuffer

2 task related API s

Task creation and deletion API

API functions for task creation and deletion mainly include xTaskCreate(), xTaskCreateStatic(), xTaskCreateRestricted(), vTaskDelete()

  • Dynamic task creation xTaskCreate()
    BaseType_t xTaskCreate( TaskFunction_t                 pxTaskCode,         //Task function
                            const char * const             pcName,             //Task name, length limited
                            const configSTACK_DEPTH_TYPE   usStackDepth,       //The task stack size actually applied for is 4 times that of ussackdepth
                            void * const                   pvParameters,       //Parameters passed to the task function
                            UBaseType_t                    uxPriority,         //Task priority
                            TaskHandle_t * const           pxCreatedTask)      //task handle 

Return value
pdPASS: task created successfully

errCOULD_NOT...: Task creation failed, out of memory

  • Static task creation xtask createstatic()
    TaskHandle_t xTaskCreateStatic( TaskFunction_t         pxTaskCode,         //Task function
                                    const char * const     pcName,             //Task name, length limited
                                    const uint32_t         ulStackDepth,       //The task stack size actually applied for is 4 times that of ussackdepth
                                    void * const           pvParameters,       //Parameters passed to the task function
                                    UBaseType_t            uxPriority,         //Task priority
                                    StackType_t * const    puxStackBuffer,     //task stack 
                                    StaticTask_t * const   pxTaskBuffer )      //Task control block

Return value
NULL: task creation failed. This error will occur when puxStackBuffer or pxTaskBuffer is NULL
Other values: the task is created successfully, and the handle of the task is returned

  • Create tasks with MPU restrictions xtask createrestricted()

  • Delete task vTaskDelete()

void vTaskDelete( TaskHandle_t xTaskToDelete ) //The task handle of the task to delete

API task suspend and resume

The task suspension and recovery API mainly uses three functions: vtask suspend(), vtask resume(), vtask resumefromisr()

  • Suspend task vtask suspend()
void vTaskSuspend( TaskHandle_t xTaskToSuspend ) //The task handle of the task to suspend

When creating a task, a task handle will be assigned to each task.

  • If you use the dynamic creation function xTaskCreate() to create a task, the parameter pxCreatedTask of the function is the task handle of the task.

  • If you use the static creation function xTaskCreateStatic() to create a task, the return value of the function is the task handle of the task.

  • Resume task vtask resume()

void vTaskResume( TaskHandle_t xTaskToResume ) //Task handle to recover
  • Resume the operation of a task in the interrupt service function vtask resumefromisr()

The interrupted version of vTaskResume(), which is used to resume the task in the interruption

BaseType_t vTaskResumeFromISR( TaskHandle_t xTaskToResume ) //Task handle to recover

Return value
pdTRUE the task priority of the resumed task is equal to or higher than that of the currently running task (interrupted task), which means that a context switch must be performed after the interrupt service function is introduced
pdFALSE the priority of the resumed task is lower than that of the current task, and context switching is not required

3 experiment

Creating tasks using dynamic methods

Create tasks by assigning task priority, task stack size, and task handle

for example

//Task priority
#define START_TASK_PRIO 1
//Task stack size
#define START_STK_SIZE 128
//task handle 
TaskHandle_t StartTask_Handler;
//Task function
void start_task(void *pvParameters);

Create a start task, create two tasks respectively, and then delete the start task

    //Create start task
    xTaskCreate((TaskFunction_t )start_task,            //Task function
                (const char*    )"start_task",          //Task name
                (uint16_t       )START_STK_SIZE,        //Task stack size
                (void*          )NULL,                  //Parameters passed to the task function
                (UBaseType_t    )START_TASK_PRIO,       //Task priority
                (TaskHandle_t*  )&StartTask_Handler);   //task handle 
    vTaskStartScheduler();          //Turn on task scheduling

Start task function

//Start task function
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           //Enter critical zone
    //Create TASK1 task
    xTaskCreate((TaskFunction_t )task1_task,
                (const char*    )"task1_task",
                (uint16_t       )TASK1_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )TASK1_TASK_PRIO,
                (TaskHandle_t*  )&Task1Task_Handler);
    //Create TASK2 task
    xTaskCreate((TaskFunction_t )task2_task,
                (const char*    )"task2_task",
                (uint16_t       )TASK2_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )TASK2_TASK_PRIO,
                (TaskHandle_t*  )&Task2Task_Handler);
    vTaskDelete(StartTask_Handler); //Delete start task
    taskEXIT_CRITICAL();            //Exit critical zone
}

Two task functions

//task1 task function
void task1_task(void *pvParameters)
{
	u8 task1_num=0;
	
	POINT_COLOR = BLACK;

	LCD_DrawRectangle(5,110,115,314); 	//Draw a rectangle	
	LCD_DrawLine(5,130,115,130);		//Draw a line
	POINT_COLOR = BLUE;
	LCD_ShowString(6,111,110,16,16,"Task1 Run:000");
	while(1)
	{
		task1_num++;	//Task execution times plus 1 pay attention to Task1_ When num1 is added to 255, it will be cleared!!
		LED0=!LED0;
		printf("Task 1 has been performed:%d second\r\n",task1_num);
		if(task1_num==5) 
		{
      vTaskDelete(Task2Task_Handler);//Task 1 execute 5 times delete task 2
			printf("Task 1 deleted task 2!\r\n");
		}
		LCD_Fill(6,131,114,313,lcd_discolor[task1_num%14]); //Filled area
		LCD_ShowxNum(86,111,task1_num,3,16,0x80);	//Displays the number of task executions
    vTaskDelay(1000);                           //Delay 1s, that is, 1000 clock beats	
	}
}

//task2 task function
void task2_task(void *pvParameters)
{
	u8 task2_num=0;
	
	POINT_COLOR = BLACK;

	LCD_DrawRectangle(125,110,234,314); //Draw a rectangle	
	LCD_DrawLine(125,130,234,130);		//Draw a line
	POINT_COLOR = BLUE;
	LCD_ShowString(126,111,110,16,16,"Task2 Run:000");
	while(1)
	{
		task2_num++;	//Task 2 execution times plus 1 pay attention to Task1_ When num2 is added to 255, it will be cleared!!
    LED1=!LED1;
		printf("Task 2 has been performed:%d second\r\n",task2_num);
		LCD_ShowxNum(206,111,task2_num,3,16,0x80);  //Displays the number of task executions
		LCD_Fill(126,131,233,313,lcd_discolor[13-task2_num%14]); //Filled area
    vTaskDelay(1000);                           //Delay 1s, that is, 1000 clock beats	
	}
	
}

Create task using static method

Before using the static creation method, set freertosconfig H macro definition configSUPPORT_STATIC_ALLOCATION

Define more task stacks and task control blocks than dynamic tasks, such as

//Task priority
#define START_TASK_PRIO 1
//Task stack size
#define START_STK_SIZE  128
//task stack 
StackType_t StartTaskStack[START_STK_SIZE];
//Task control block
StaticTask_t StartTaskTCB;
//task handle 
TaskHandle_t StartTask_Handler;
//Task function
void start_task(void *pvParameters);

Other steps are similar

Suspend and restore

Topics: Operating System FreeRTOS