天天看点

FreeRTOS(一)动态任务创建

任务创建函数的本质就是创建新任务并初始化,最后将它放入任务就绪列表

vTaskCreate()动态创建任务函数

/*vTaskCreate()动态创建任务函数
  参数1:任务入口
  参数2:任务名称
  参数3:任务栈大小:单位为字
  参数4:任务形参
  参数5:任务优先级
  参数6:任务句柄
  */
	BaseType_t xTaskCreate(	TaskFunction_t pxTaskCode,
							const char * const pcName,
							const uint16_t usStackDepth,
							void * const pvParameters,
							UBaseType_t uxPriority,
							TaskHandle_t * const pxCreatedTask )
	{
			TCB_t *pxNewTCB;     //定义任务控制块指针
			BaseType_t xReturn;  //定义任务句柄用于指向任务的TCB
			StackType_t *pxStack;//定义堆栈指针
			//为堆栈申请内存
			pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); 
			if( pxStack != NULL )
			{
				//给任务控制块申请内存
				pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
				if( pxNewTCB != NULL )
				{
					//若任务控制块内存申请成功,任务控制块的任务栈起始地址等于堆栈指针
					pxNewTCB->pxStack = pxStack;
				}
				else
				{
					vPortFree( pxStack );
				}
			}
			else
			{
				pxNewTCB = NULL;
			}
		}
		if( pxNewTCB != NULL )
		{
			//如果任务控制块创建成功,初始化任务
			prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL );
			//将任务控制块添加到就绪列表中
			prvAddNewTaskToReadyList( pxNewTCB );
			xReturn = pdPASS;
		}
		else
		{
			xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
		}

		return xReturn;
	}

           

prvInitialiseNewTask()初始化新任务函数

/*
prvInitialiseNewTask()
参数1:任务入口
参数2:任务名称
参数3:任务栈大小
参数4:任务形参
参数5:任务优先级
参数6:任务句柄
参数7:任务控制块指针
参数8:获取栈顶地址
*/
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;
	//初始化堆栈为0xa5,用于堆栈溢出检测
	( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) ulStackDepth * sizeof( StackType_t ) );
	//获取栈顶地址,由于堆栈向下增长,即由高地址向低地址增长,则栈顶地址为栈起始地址加任务栈长度-1
	pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
	//栈顶指针向下做8字节对齐,即找到栈顶大小%8=0的位置为栈顶地址
	pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
	
	//将任务名储存在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();
		}
	}
	pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0';
	//若输入任务优先级大于最大优先级,则强制设为32—1
	if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
	{
		uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}
	//将任务优先级存储到TCB中
	pxNewTCB->uxPriority = uxPriority;
	
	//初始化TCB的状态列表和事件列表:设置两个节点所在的链表为空,表示该节点没有插入到链表
	vListInitialiseItem( &( pxNewTCB->xStateListItem ) );
	vListInitialiseItem( &( pxNewTCB->xEventListItem ) );
	
	//将任务块状态列表项,也就是任务节点挂载到pxNewTCB
	listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB );
	//初始化节点排序辅助值,为最大优先级-输入优先级
	listSET_LIST_ITEM_VALUE( &( pxNewTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority ); 
	//将任务块事件列表项挂载到pxNewTCB
	listSET_LIST_ITEM_OWNER( &( pxNewTCB->xEventListItem ), pxNewTCB );
	//初始化任务堆栈
	pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
	
	//让任务句柄指向任务控制块
	if( ( void * ) pxCreatedTask != NULL )
	{
		*pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}
}
           

pxPortInitialiseStack()堆栈初始化函数

StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{
	pxTopOfStack--; //堆栈指针减一,指针初始指在栈顶
	*pxTopOfStack = portINITIAL_XPSR;	栈顶下面存入portINITIAL_XPSR的值,为0x01000000 
	pxTopOfStack--;
	*pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK;	/* r15(程序计数器PC)寄存器保存任务入口地址*/
	pxTopOfStack--;
	*pxTopOfStack = ( StackType_t ) prvTaskExitError;	/* r14(链接寄存器LR)寄存器保存任务的返回地址,若返回则跳转无限循环*/

	pxTopOfStack -= 5;	/* R12, R3, R2 and R1默认初始化为0. */
	*pxTopOfStack = ( StackType_t ) pvParameters;	/* R0保存任务形参 */
	pxTopOfStack -= 8;	/* R11, R10, R9, R8, R7, R6, R5 and R4. */

	return pxTopOfStack; //返回堆栈指针,最后指向r4
}
           

prvAddNewTaskToReadyList()添加新任务到就绪列表

static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
{
	taskENTER_CRITICAL();
	{
		uxCurrentNumberOfTasks++; //当前任务数加一
		//pxCurrentTCB是全局变量表示当前任务,若为空则表示当前没有任务,可能是创建第一个任务
		if( pxCurrentTCB == NULL ) 
		{
			pxCurrentTCB = pxNewTCB;  
			if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )
			{
				若当前任务为一,则表示这是第一个任务,初始化就绪列表
				prvInitialiseTaskLists();
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		else
		{
			//若任务调度器没有运行
			if( xSchedulerRunning == pdFALSE )
			{
				//判断当前任务优先级与新任务优先级大小,若新任务大,则当前任务为新任务
				if( pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority )
				{
					pxCurrentTCB = pxNewTCB;
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		
		uxTaskNumber++;  //全局变量,初始为0,记录任务数
		pxNewTCB->uxTCBNumber = uxTaskNumber; TCB的任务标号等于任务数字
		
		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();
	}
}
           

prvInitialiseTaskLists()初始化就绪列表

static void prvInitialiseTaskLists( void )
{
	UBaseType_t uxPriority;
	//优先级从0开始遍历至最大优先级,逐个初始化就绪列表
	for( uxPriority = ( UBaseType_t ) 0U; uxPriority < ( UBaseType_t ) configMAX_PRIORITIES; uxPriority++ )
	{
		vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) );
	}
	//初始化两个延时任务列表
	vListInitialise( &xDelayedTaskList1 );
	vListInitialise( &xDelayedTaskList2 );
	//初始化就绪态任务暂存列表
	vListInitialise( &xPendingReadyList );
	
	//将延时任务列表1赋给当前工作延时列表
	pxDelayedTaskList = &xDelayedTaskList1;
	//将延时任务列表2赋给溢出链表
	pxOverflowDelayedTaskList = &xDelayedTaskList2;
}
           

prvAddTaskToReadyList()添加任务至就绪列表

/*1.根据任务优先级将uxTopReadyPriority相应的位至1
  2.根据优先级将任务末尾插入就绪列表pxReadyTasksLists[]相应的位置*/
#define prvAddTaskToReadyList( pxTCB )																\
	traceMOVED_TASK_TO_READY_STATE( pxTCB );														\
	taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority );												\
	vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) ); \
	tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB )