当前位置:网站首页>FreeRTOS personal notes - create / delete dynamic tasks, start scheduler
FreeRTOS personal notes - create / delete dynamic tasks, start scheduler
2022-07-23 23:16:00 【Couvrir wild beast】
According to personal learning direction , Study FreeRTOS. Because brother wildfire FreeRTOS It's more implicit , I intend to be as detailed as possible in this column . As a personal note , For reference or reference only .
mixed material item :FreeRTOS Kernel Implementation and application development practice guide 、 Wildfire FreeRTOS Supporting video source code 、b Standing wildfire FreeRTOS video . It's better to match it !!!
Create and delete dynamic tasks
Creation of dynamic tasks
Whether it is static creation or dynamic creation of tasks , It's all from SRAM District . The static creation task comes from SRAM Stack of areas , Dynamically create tasks from SRAM Total heap of the zone .
The definition of total heap comes from FreeRTOSConfig.h, This was mentioned in the last section .
// The total heap size of the system
#define configTOTAL_HEAP_SIZE ((size_t)(36*1024))
static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];Create task functions dynamically xTaskCreate()
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, // Function entrance
const char * const pcName, // The name of the function
const configSTACK_DEPTH_TYPE usStackDepth, // Function size , The unit is byte
void * const pvParameters, // Function parameter
UBaseType_t uxPriority, // Function priority
TaskHandle_t * const pxCreatedTask ) // Task to handle
{
TCB_t *pxNewTCB;
BaseType_t xReturn;
#if( portSTACK_GROWTH > 0 )
{
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
if( pxNewTCB != NULL )
{
pxNewTCB->pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) );
if( pxNewTCB->pxStack == NULL )
{
vPortFree( pxNewTCB );
pxNewTCB = NULL;
}
}
}
#else /* portSTACK_GROWTH */
{
StackType_t *pxStack;
// Allocate space for the stack used by the task being created , Open a stack for the task being created
pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) );
if( pxStack != NULL )
{
// Assigned tasks TCB
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
if( pxNewTCB != NULL )
{
pxNewTCB->pxStack = pxStack;
}
else
{
// Release stack
vPortFree( pxStack );
}
}
else
{
pxNewTCB = NULL;
}
}
#endif /* portSTACK_GROWTH */
if( pxNewTCB != NULL )
{
#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
{
pxNewTCB->ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB;
}
#endif /* configSUPPORT_STATIC_ALLOCATION */
prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL ); // Create a new task
prvAddNewTaskToReadyList( pxNewTCB ); // Add to ready list
xReturn = pdPASS;
}
else
{
xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
}
return xReturn;
}Allocate memory function pvPortMalloc()
void *pvPortMalloc( size_t xWantedSize )
{
BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
void *pvReturn = NULL;
vTaskSuspendAll();
{
// If that's right malloc The first call of , Then the heap will need to be initialized to set the free block list
if( pxEnd == NULL )
{
prvHeapInit();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* Omit code */
}
( void ) xTaskResumeAll();
/* Omit code */
return pvReturn;
}Heap initialization function prvHeapInit()
//#define portBYTE_ALIGNMENT_MASK ( 0x0007 )
//#define portBYTE_ALIGNMENT 8
//static const size_t xHeapStructSize = ( sizeof( BlockLink_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
static void prvHeapInit( void )
{
BlockLink_t *pxFirstFreeBlock;
uint8_t *pucAlignedHeap;
size_t uxAddress;
size_t xTotalHeapSize = configTOTAL_HEAP_SIZE;
//static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
uxAddress = ( size_t ) ucHeap;
/* Ensure that the heap starts on the correctly aligned boundary */
if( ( uxAddress & portBYTE_ALIGNMENT_MASK ) != 0 )
{
uxAddress += ( portBYTE_ALIGNMENT - 1 );
uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
xTotalHeapSize -= uxAddress - ( size_t ) ucHeap;
}
pucAlignedHeap = ( uint8_t * ) uxAddress;
//xStart Used to save the pointer to the first task in the free block list ,void Used to prevent compiler warnings
xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap;
xStart.xBlockSize = ( size_t ) 0;
//pxEnd Used to mark the end of the free block list , And insert the end of the heap space
uxAddress = ( ( size_t ) pucAlignedHeap ) + xTotalHeapSize;
uxAddress -= xHeapStructSize;
uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
pxEnd = ( void * ) uxAddress;
pxEnd->xBlockSize = 0;
pxEnd->pxNextFreeBlock = NULL;
// First , There is a free block , Its size can take up the whole heap space , subtract pxEnd Occupied space
pxFirstFreeBlock = ( void * ) pucAlignedHeap;
pxFirstFreeBlock->xBlockSize = uxAddress - ( size_t ) pxFirstFreeBlock;
pxFirstFreeBlock->pxNextFreeBlock = pxEnd;
// There is only one block - It covers the entire available heap space . Because it is just initialized heap memory
xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );
} Suppose you create a task in the critical area , The task can only execute the highest priority task when it exits the critical area .
If the critical zone is not used , There will be three situations :
1、 The priority of the application task is higher than that of the initial task , After that, immediately execute the application task just created , When the application task is blocked , Continue to return to the place where the initial task was interrupted and continue to execute , Until all application tasks are created , Finally, the initial task deletes itself , Accomplish your mission ;
2、 The priority of the application task is the same as that of the initial task , After creation, execute according to the time slice of the task , Until all application tasks are created , Finally, the initial task deletes itself , Accomplish your mission ;
3、 The priority of the application task is lower than that of the initial task , The task will not be executed after creation .
Dynamic task creation instance , The above functions are officially encapsulated , We use it directly .
/* Create a task handle */
static TaskHandle_t AppTaskCreate_Handle = NULL;
/* LED Task to handle */
static TaskHandle_t LED_Task_Handle = NULL;
int main()
{
/* Omit initialization */
/* establish AppTaskCreate Mission */
xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate, /* Task entry function */
(const char* )"AppTaskCreate", /* Task name */
(uint16_t )512, /* Task stack size */
(void* )NULL, /* Task entry function parameters */
(UBaseType_t )1, /* Task priority */
(TaskHandle_t* )&AppTaskCreate_Handle);/* Task control block pointer */
/* Start task scheduling */
if (pdPASS == xReturn)
vTaskStartScheduler(); /* Start the task , Turn on scheduling */
else
return -1;
while (1); /* Normal will not be implemented here */
}Deletion of dynamic tasks
vTaskDelete() Used to delete a task . When one task deletes another , The formal parameter is the task handle returned when the task to be deleted is created , If it's deleting itself , Then the formal parameter is NULL.
To use this function, you must FreeRTOSConfig.h Zhongba INCLUDE_vTaskDelete Defined as 1, Deleted tasks will be removed from all ready tasks , Blocking , Remove from pending and event lists .
Dynamically delete task functions vTaskDelete() function
#if ( INCLUDE_vTaskDelete == 1 )
void vTaskDelete( TaskHandle_t xTaskToDelete )
{
TCB_t *pxTCB;
taskENTER_CRITICAL();
{
//#define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? ( TCB_t * ) pxCurrentTCB : ( TCB_t * ) ( pxHandle ) )
// If pxTCB = prvGetTCBFromHandle( NULL ); be pxTCB = ( TCB_t * ) pxCurrentTCB; Then the task to be deleted is the current task
// If pxTCB = prvGetTCBFromHandle( xTaskToDelete ); be pxTCB = ( TCB_t * ) xTaskToDelete; Then the task to be deleted is the specified task
pxTCB = prvGetTCBFromHandle( xTaskToDelete );
// Remove the task from the ready list , And set the priority of the task in the ready list 0
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
{
taskRESET_READY_PRIORITY( pxTCB->uxPriority );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
//listLIST_ITEM_CONTAINER Return the nodes contained in the linked list
// If the task is waiting for an event , Also remove from the waiting event list
if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
{
( void ) uxListRemove( &( pxTCB->xEventListItem ) );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
uxTaskNumber++;
/* The task is deleting itself . This cannot be accomplished within the task itself , Because the context needs to be switched to another task .
Put the task in the end list . Idle tasks will check the end list and release any memory of the deleted task control block and the stack of deleted tasks . */
if( pxTCB == pxCurrentTCB )
{
// Insert the task into the end list
vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) );
// Record how many tasks need to free memory , So that the idle task knows that there is a deleted task , Then the free task of memory release will check the end list xTasksWaitingTermination
++uxDeletedTasksWaitingCleanUp;
// Task delete hook function
portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending );
}
else
{
--uxCurrentNumberOfTasks;
prvDeleteTCB( pxTCB );
/* Reset the unblocking time of the next task . Recalculate how long it will take to perform the next task , If the next task is unlocked , It happens to be the deleted task , Then this is incorrect ,
Because the deleted task is invisible to the scheduler , Therefore, the scheduler cannot schedule the deleted tasks , So get the next task to unblock from the delay list again .
It is the task obtained from the head of the delay list TCB, The delay list is sorted by delay time */
prvResetNextTaskUnblockTime();
}
traceTASK_DELETE( pxTCB );
}
taskEXIT_CRITICAL();
// The scheduler is running
if( xSchedulerRunning != pdFALSE )
{
if( pxTCB == pxCurrentTCB )
{
configASSERT( uxSchedulerSuspended == 0 );
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
#endif /* INCLUDE_vTaskDelete */Dynamic task delete instance , The above functions are officially encapsulated , We use it directly .
/* Create a task , Store the created task handle in DeleteHandle in */
TaskHandle_t DeleteHandle;
if (xTaskCreate(DeleteTask,
"DeleteTask",
STACK_SIZE,
NULL,
PRIORITY,
&DeleteHandle)
!= pdPASS )
{
/* Failed to create task , Because there is not enough heap memory to allocate . */
}
void DeleteTask( void )
{
/* user designation codes xxxxx */
/* ............ */
/* Delete the task itself */
vTaskDelete( NULL );
}
/* Delete in other tasks DeleteTask Mission */
vTaskDelete( DeleteHandle );Start the scheduler
After creating the task , You need to start the scheduler -vTaskStartScheduler() function .vTaskStartScheduler() Function implements idle tasks and timer tasks .
FreeRTOS Once started , It is necessary to ensure that a task in the system is running at all times (Runing), And idle tasks cannot be suspended or deleted , Idle tasks have the lowest priority , So that other tasks in the system can preempt idle tasks at any time CPU Right to use .
vTaskStartScheduler() as follows
void vTaskStartScheduler( void )
{
BaseType_t xReturn;
// Add idle tasks
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
{
StaticTask_t *pxIdleTaskTCBBuffer = NULL;
StackType_t *pxIdleTaskStackBuffer = NULL;
uint32_t ulIdleTaskStackSize;
// Get idle task stack and pointer , Use statically allocated RAM Create idle tasks
vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize );
xIdleTaskHandle = xTaskCreateStatic( prvIdleTask,
configIDLE_TASK_NAME,
ulIdleTaskStackSize,
( void * ) NULL,
( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
pxIdleTaskStackBuffer,
pxIdleTaskTCBBuffer );
if( xIdleTaskHandle != NULL )
{
xReturn = pdPASS;
}
else
{
xReturn = pdFAIL;
}
}
#else
{
// Use dynamically allocated RAM Create idle tasks
xReturn = xTaskCreate( prvIdleTask,
configIDLE_TASK_NAME,
configMINIMAL_STACK_SIZE,
( void * ) NULL,
( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
&xIdleTaskHandle );
}
#endif /* configSUPPORT_STATIC_ALLOCATION */
#if ( configUSE_TIMERS == 1 )
{
// If enabled configUSE_TIMERS The macro definition indicates the use of a timer , Need to create timer task */
if( xReturn == pdPASS )
{
xReturn = xTimerCreateTimerTask();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* configUSE_TIMERS */
if( xReturn == pdPASS )
{
/* Omit code */
// Close the interrupt , To ensure that no interruption occurs
// Calling xPortStartScheduler() Before or during . The task of creating the stack contains the state of opening the interrupt
// therefore , When the first task , The interrupt will automatically re enable and start running
portDISABLE_INTERRUPTS();
/* Omit code */
xNextTaskUnblockTime = portMAX_DELAY;
xSchedulerRunning = pdTRUE;
xTickCount = ( TickType_t ) 0U;
/* Omit code */
// call xPortStartScheduler Function configuration related hardware , Such as tick timer 、 FPU、 pendsv etc.
if( xPortStartScheduler() != pdFALSE )
{
// The successful running , Will not run here
}
else
{
// It won't run here , Unless calls xTaskEndScheduler() function
}
}
else
{
// This line is only reached if the kernel cannot be started , Because there is not enough heap memory to create idle tasks or timer tasks
// Assertions are used here , Will output error messages , Facilitate error location
configASSERT( xReturn != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY );
}
( void ) xIdleTaskHandle;
}When starting the task scheduler , If the startup is successful , The task will not return , If the startup fails , Through LR Register specified address exit , Creating AppTaskCreate During the mission , Task stack correspondence LR The register points to the task exit function prvTaskExitError(), There is an endless loop in this function , This means that if the creation task fails , It's going to go into a dead cycle , The task will not run .
Create timer task function xTimerCreateTimerTask() as follows
BaseType_t xTimerCreateTimerTask( void )
{
BaseType_t xReturn = pdFAIL;
// Check the list of activity timers used , And a queue for communicating with the timer service
prvCheckForValidListAndQueue();
if( xTimerQueue != NULL )
{
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
{
StaticTask_t *pxTimerTaskTCBBuffer = NULL;
StackType_t *pxTimerTaskStackBuffer = NULL;
uint32_t ulTimerTaskStackSize;
vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &ulTimerTaskStackSize );
xTimerTaskHandle = xTaskCreateStatic( prvTimerTask,
configTIMER_SERVICE_TASK_NAME,
ulTimerTaskStackSize,
NULL,
( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,
pxTimerTaskStackBuffer,
pxTimerTaskTCBBuffer );
if( xTimerTaskHandle != NULL )
{
xReturn = pdPASS;
}
}
#else
{
xReturn = xTaskCreate( prvTimerTask,
configTIMER_SERVICE_TASK_NAME,
configTIMER_TASK_STACK_DEPTH,
NULL,
( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,
&xTimerTaskHandle );
}
#endif /* configSUPPORT_STATIC_ALLOCATION */
}
else
{
mtCOVERAGE_TEST_MARKER();
}
configASSERT( xReturn );
return xReturn;
}All functions in this section are encapsulated , It can be used directly .
Create tasks dynamically and use xTaskCreate()
Dynamically delete tasks directly with vTaskDelete()
Start the scheduler vTaskStartScheduler( )
边栏推荐
- Build your own target detection environment, model configuration, data configuration mmdetection
- Contemporary inspirational "women"
- Programming in the novel [serial 17] the moon bends in the yuan universe
- Tap series article 9 | application development accelerator
- QT set cache and compile output path
- Tap series article 6 | application model of tap
- strncat() strncmp()
- Rails搭配OSS最佳实践
- Tap series article 4 | backstage based tap developer portal
- USB转CAN设备在核酸提取仪 高性能USB接口CAN卡
猜你喜欢

TAP 系列文章9 | 应用开发加速器

Diabetes genetic risk testing challenge advanced

Sword finger offer II 115. reconstruction sequence

dried food! Implicit sparse regularization effect in neural networks

Principal component analysis (matlab)

Light up the LED light of little bear patting learning

FL Studio 20.9 update Chinese version host Daw digital audio workstation

Basic operations of AutoCAD

Tap series article 5 | cloud native build service

作为开发,你不得不知道的三个性能测试工具|Jmeter、Apipost、JMH使用指南
随机推荐
2022-7-22 face review + simple topic sorting
Introduction to mysqlbinlog command (remote pull binlog)
Detailed explanation of pseudo instructions in assembly language (with examples)
TOPSIS method (matlab)
[unity3d daily bug] unity3d solves "the type or namespace name" XXX "cannot be found (are you missing the using directive or assembly reference?)" Etc
TAP 系列文章5 | 云原生构建服务
Excel password related
Brief analysis of compiling principle of.Net CLR R2R
Classification model - logistic regression, Fisher linear discriminant (SPSS)
激光雷达点云数据录制的rosbag文件转换成csv文件
糖尿病遗传风险检测挑战赛进阶
ospf终极实验——学会ospf世纪模板例题
Notes on network segment CIDR
Redis pipeline technology / partition
Build your own target detection environment, model configuration, data configuration mmdetection
在openEuler社区开源的Embedded SIG,来聊聊它的多 OS 混合部署框架
Galaxy Securities opens an account online. Is it safe to open an account on your mobile phone
The canfd/can interface offline burning operation instructions of h7-tool have been updated (2022-07-12)
Rosbag file recorded by LIDAR point cloud data is converted into CSV file
Getting started database days2