FreeRTOS 创建静态任务

本文详细介绍了如何使用xTaskCreateStatic在FreeRTOS中静态创建任务,包括任务栈分配、TCB结构与初始化过程。重点讲解了TCB的作用和内存管理,适合理解RTOS任务调度机制的开发者阅读。
摘要由CSDN通过智能技术生成

范例:使用 xTaskCreateStatic 静态创建任务

	// Dimensions the buffer that the task being created will use as its stack.
	#define STACK_SIZE 200

	// Structure that will hold the TCB of the task being created.
	StaticTask_t xTaskBuffer;

	// Buffer that the task being created will use as its stack. 
	StackType_t xStack[ STACK_SIZE ];

	// Function that implements the task being created.
	void vTaskCode( void * pvParameters )
	{
		configASSERT( ( uint32_t ) pvParameters == 1UL );
		for( ;; )
		{
			// Task code goes here.
		}
	}

	// Function that creates a task.
	void vOtherFunction( void )
	{
		TaskHandle_t xHandle = NULL;
		xHandle = xTaskCreateStatic(
					  vTaskCode,       // Function that implements the task.
					  "NAME",          // Text name for the task.
					  STACK_SIZE,      // Stack size in words, not bytes.
					  ( void * ) 1,    // Parameter passed into the task.
					  tskIDLE_PRIORITY,// Priority at which the task is created.
					  xStack,          // Array to use as the task's stack.
					  &xTaskBuffer );  // Variable to hold the task's data structure.

		vTaskSuspend( xHandle );
	}

Internally, within the FreeRTOS implementation, tasks use two blocks of memory. The first block is used to hold the task’s data structures. The second block is used by the task as its stack. If a task is created using xTaskCreateStatic() then the application writer must provide the required memory. xTaskCreateStatic() therefore allows a task to be created without using any dynamic memory allocation.

TCB

/*
 * Task control block.  A task control block (TCB) is allocated for each task,
 * and stores task state information, including a pointer to the task's context
 * (the task's run time environment, including register values)
 */
typedef struct tskTaskControlBlock
{
	volatile StackType_t *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. */

	ListItem_t xStateListItem;	/*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
	ListItem_t xEventListItem;	/*< Used to reference a task from an event list. */
	UBaseType_t uxPriority;		/*< The priority of the task.  0 is the lowest priority. */
	StackType_t *pxStack;		/*< Points to the start of the stack. */
	char pcTaskName[configMAX_TASK_NAME_LEN]; /*< Descriptive name given to the task when created. */
	StackType_t	*pxEndOfStack;	/*< Points to the end of the stack on architectures where the stack grows up from low memory. */
	
} tskTCB;

typedef tskTCB TCB_t;

静态创建任务 xTaskCreateStatic 的源码

	TaskHandle_t xTaskCreateStatic(	TaskFunction_t pxTaskCode,
									const char * const pcName,
									const uint32_t ulStackDepth,
									void * const pvParameters,
									UBaseType_t uxPriority,
									StackType_t * const puxStackBuffer,
									StaticTask_t * const pxTaskBuffer ) 
	{
		TCB_t *pxNewTCB;
		TaskHandle_t xReturn;

		configASSERT( puxStackBuffer != NULL );
		configASSERT( pxTaskBuffer != NULL );

		if( ( pxTaskBuffer != NULL ) && ( puxStackBuffer != NULL ) )
		{
			pxNewTCB = ( TCB_t * ) pxTaskBuffer; 
			pxNewTCB->pxStack = ( StackType_t * ) puxStackBuffer;
		prvInitialiseNewTask( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, &xReturn, pxNewTCB, NULL );
			prvAddNewTaskToReadyList( pxNewTCB );
		}
		else
		{
			xReturn = NULL;
		}

		return xReturn;
	}

设置列表项owner和value的宏定义

/*
 * Access macro to set the owner of a list item.  The owner of a list item
 * is the object (usually a TCB) that contains the list item.
 */
#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner )		( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )
/*
 * Access macro to set the value of the list item.  In most cases the value is
 * used to sort the list in descending order.
 */
#define listSET_LIST_ITEM_VALUE( pxListItem, xValue )	( ( pxListItem )->xItemValue = ( xValue ) )

列表声明

/*
 * Definition of the only type of object that a list can contain.
 */
struct xLIST_ITEM
{		
	/*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
	listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE	
	/*< The value being listed.  In most cases this is used to sort the list in descending order. */
	configLIST_VOLATILE TickType_t xItemValue;	
	/*< Pointer to the next ListItem_t in the list. */
	struct xLIST_ITEM * configLIST_VOLATILE pxNext;	
	/*< Pointer to the previous ListItem_t in the list. */
	struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;								
	/*< Pointer to the object (normally a TCB) that contains the list item.  There is therefore a two way link between the object containing the list item and the list item itself. */
	void * pvOwner;			
	/*< Pointer to the list in which this list item is placed (if any). */
	void * configLIST_VOLATILE pvContainer;		
	/*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
	listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE	
};			
/* For some reason lint wants this as two separate definitions. */
typedef struct xLIST_ITEM ListItem_t;	

初始化任务列表

static void prvInitialiseNewTask( 	TaskFunction_t pxTaskCode,
									const char * const pcName,
									const uint32_t ulStackDepth,
									void * const pvParameters,
									UBaseType_t uxPriority,
									TaskHandle_t * const pxCreatedTask,
									TCB_t *pxNewTCB,
									const MemoryRegion_t * const xRegions ) 
{
	StackType_t *pxTopOfStack;
	UBaseType_t x;

	/* Calculate the top of stack address.  */
	{
		pxTopOfStack = pxNewTCB->pxStack;

		/* Check the alignment of the stack buffer is correct. */
		configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxNewTCB->pxStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );

		/* The other extreme of the stack space is required if stack checking is performed. */
		pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
	}

	/* Store the task name in the TCB. */
	for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
	{
		pxNewTCB->pcTaskName[ x ] = pcName[ x ];

		if( pcName[ x ] == 0x00 )
		{
			break;
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}

	/* Ensure the name string is terminated in the case that the string length
	was greater or equal to configMAX_TASK_NAME_LEN. */
	pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0';

	/* This is used as an array index so must ensure it's not too large.  First
	remove the privilege bit if one is present. */
	if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
	{
		uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}

	pxNewTCB->uxPriority = uxPriority;

	vListInitialiseItem( &( pxNewTCB->xStateListItem ) );
	vListInitialiseItem( &( pxNewTCB->xEventListItem ) );

	/* Set the pxNewTCB as a link back from the ListItem_t.  This is so we can get
	back to	the containing TCB from a generic item in a list. */
	listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB );

	/* Event lists are always in priority order. */
	listSET_LIST_ITEM_VALUE( &( pxNewTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority ); 
	listSET_LIST_ITEM_OWNER( &( pxNewTCB->xEventListItem ), pxNewTCB );


	{
		/* Avoid compiler warning about unreferenced parameter. */
		( void ) xRegions;
	}


	/* Initialize the TCB stack to look as if the task was already running,
	but had been interrupted by the scheduler.  The return address is set
	to the start of the task function. Once the stack has been initialised
	the	top of stack variable is updated. */
	pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );

	if( ( void * ) pxCreatedTask != NULL )
	{
		/* Pass the handle out in an anonymous way.  The handle can be used to
		change the created task's priority, delete the created task, etc.*/
		*pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}
}

把新创建的任务添加的任务列表

static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
{
	taskENTER_CRITICAL();
	{
		uxCurrentNumberOfTasks++;
		if( pxCurrentTCB == NULL )
		{
			pxCurrentTCB = pxNewTCB;
			
			/* This is the first task to be created so do the preliminary initialisation required.*/
			if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )   
			{
				prvInitialiseTaskLists();
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		else
		{
			/* If the scheduler is not already running, make this task the
			current task if it is the highest priority task to be created
			so far. */
			if( xSchedulerRunning == pdFALSE )
			{
				if( pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority )
				{
					pxCurrentTCB = pxNewTCB;
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}

		uxTaskNumber++;
		traceTASK_CREATE( pxNewTCB );
		prvAddTaskToReadyList( pxNewTCB );
		portSETUP_TCB( pxNewTCB );
	}
	taskEXIT_CRITICAL();

	if( xSchedulerRunning != pdFALSE )
	{
		if( pxCurrentTCB->uxPriority < pxNewTCB->uxPriority )
		{
			taskYIELD_IF_USING_PREEMPTION();
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}
}

定义任务数量为0

PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks 	= ( UBaseType_t ) 0U;
PRIVILEGED_DATA static UBaseType_t uxTaskNumber 					= ( UBaseType_t ) 0U;

初始化列表 list

/*
 * Utility to ready all the lists used by the scheduler.  This is called
 * automatically upon the creation of the first task.
 */
static void prvInitialiseTaskLists( void )
{
	UBaseType_t uxPriority;

	for( uxPriority = ( UBaseType_t ) 0U; uxPriority < ( UBaseType_t ) configMAX_PRIORITIES; uxPriority++ )
	{
		vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) );
	}

	vListInitialise( &xDelayedTaskList1 );
	vListInitialise( &xDelayedTaskList2 );
	vListInitialise( &xPendingReadyList );

	/* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList using list2. */
	pxDelayedTaskList = &xDelayedTaskList1;
	pxOverflowDelayedTaskList = &xDelayedTaskList2;
}

全局变量声明

/* Lists for ready and blocked tasks. --------------------*/
/*< Prioritised ready tasks. */
PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ];
/*< Delayed tasks. */
PRIVILEGED_DATA static List_t xDelayedTaskList1;
/*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */						
PRIVILEGED_DATA static List_t xDelayedTaskList2;						
/*< Tasks that have been readied while the scheduler was suspended.  They will be moved to the ready list when the scheduler is resumed. */
PRIVILEGED_DATA static List_t xPendingReadyList;						
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值