天天看點

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 )