freertos 任务创建 xTaskCreate xTaskGenericCreate 源代码分析

任务定义

//宏定义 任务创建函数
#define xTaskCreate( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ) xTaskGenericCreate( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( pxCreatedTask ), ( NULL ), ( NULL ) )

 

//任务 创建任务
signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode,///指向任务的入口函数. 
     const signed char * const pcName,  //描述任务的名字。主要便于调试
     unsigned short usStackDepth, //指定任务堆栈的深度
      void *pvParameters, //指针用于作为一个参数传向创建的任务
      unsigned portBASE_TYPE uxPriority, //任务运行时的优先级
      xTaskHandle *pxCreatedTask, //用于传出任务的句柄,在API对该创建出来的任务进行引用如改变任务优先级
      portSTACK_TYPE *puxStackBuffer,  //堆栈缓冲区
      const xMemoryRegion * const xRegions /*缓存区*/ )
{
signed portBASE_TYPE xReturn;
tskTCB * pxNewTCB;

	configASSERT( pxTaskCode );
	configASSERT( ( ( uxPriority & ( ~portPRIVILEGE_BIT ) ) < configMAX_PRIORITIES ) );

	/* 为TCB 和 堆栈分配空间 */ 
	pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer );

	if( pxNewTCB != NULL )  /* 如果 TCB 空间分配成功 */ 
	{
		portSTACK_TYPE *pxTopOfStack;

		#if( portUSING_MPU_WRAPPERS == 1 )
			/* Should the task be created in privileged mode? 特权模式 */
			portBASE_TYPE xRunPrivileged;
			if( ( uxPriority & portPRIVILEGE_BIT ) != 0U )
			{
				xRunPrivileged = pdTRUE;
			}
			else
			{
				xRunPrivileged = pdFALSE;
			}
			uxPriority &= ~portPRIVILEGE_BIT;
		#endif /* portUSING_MPU_WRAPPERS == 1 */

		
    /* 计算堆栈栈顶的位置 */ 
		#if( portSTACK_GROWTH < 0 )
		{
			pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - ( unsigned short ) 1 );
			/* pxStack 指向堆栈的起始地址 */
			pxTopOfStack = ( portSTACK_TYPE * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ( portPOINTER_SIZE_TYPE ) ~portBYTE_ALIGNMENT_MASK  ) ); /*lint !e923 MISRA exception.  Avoiding casts between pointers and integers is not practical.  Size differences accounted for using portPOINTER_SIZE_TYPE type. */
			/* 堆栈有地址对齐的要求 */
			
			/*内存对齐 */
			configASSERT( ( ( ( unsigned long ) pxTopOfStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
		}
		#else /* portSTACK_GROWTH */
		{
			pxTopOfStack = pxNewTCB->pxStack;
			/* 新建的堆栈是空的,所以堆栈的栈顶就在起始地址处(正生堆栈)*/ 

			/* 内存对齐 */
			configASSERT( ( ( ( unsigned long ) pxNewTCB->pxStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );

			/* If we want to use stack checking on architectures that use
			a positive stack growth direction then we also need to store the
			other extreme of the stack space. */
			
			 /* 如果要做堆栈检查,就要知道堆栈的另一端界限在哪里 */ 
			pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
		}
		#endif /* portSTACK_GROWTH */

		 /* 设置 TCB 的各个部分 */ 
		prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth );
		/* 初始化堆栈,使得任务好像被中断函数中断了一样,中断返回地址就是任务的首地址 */
		/*一旦被初始化堆栈顶部的堆栈变量将被更新。 */
		
		/* 初始化任务堆栈,并将返回地址保存在tcb中的pxTopOfStack变量*/
		#if( portUSING_MPU_WRAPPERS == 1 )
		{
			pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
		}
		#else /* portUSING_MPU_WRAPPERS */
		{
   //汇编语言对堆栈进行初始化
			pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
		}
		#endif /* portUSING_MPU_WRAPPERS */

		if( ( void * ) pxCreatedTask != NULL )  //任务句柄
		{
			/* 返回任务的句柄 */ 
			*pxCreatedTask = ( xTaskHandle ) pxNewTCB;
		}

		 /*关中断*/
		taskENTER_CRITICAL();
		{ /*更新系统的任务数*/
			uxCurrentNumberOfTasks++;
			if( pxCurrentTCB == NULL )
			{
				/* 没有其他任务, 或者其他任务在挂起状态 设为当前任务 */
				pxCurrentTCB =  pxNewTCB;

				if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )
				{
					//这是第一个任务,初始化任务状态切换调度时使用的几个链表
					prvInitialiseTaskLists();
				}
			}
			else
			{
				/* 如果调度没有运行使得当前任务为最高级任务 */
				if( xSchedulerRunning == pdFALSE )
				{
					if( pxCurrentTCB->uxPriority <= uxPriority )
					{
						pxCurrentTCB = pxNewTCB;
					}
				}
			}
                        if( pxNewTCB->uxPriority > uxTopUsedPriority )
			{
				uxTopUsedPriority = pxNewTCB->uxPriority;
			}
			uxTaskNumber++; 

			#if ( configUSE_TRACE_FACILITY == 1 )
			{
				/* Add a counter into the TCB 仅仅为了追踪*/
				pxNewTCB->uxTCBNumber = uxTaskNumber;
			}
			#endif /* configUSE_TRACE_FACILITY */
			traceTASK_CREATE( pxNewTCB );

			prvAddTaskToReadyList( pxNewTCB );  //添加到就绪链表中

			xReturn = pdPASS;
			portSETUP_TCB( pxNewTCB );
		}
		taskEXIT_CRITICAL();
	}
	else  //分配失败
	{
		xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
		traceTASK_CREATE_FAILED(); //无定义
	}

	if( xReturn == pdPASS )
	{
		if( xSchedulerRunning != pdFALSE )  //切换状态
		{
			if( pxCurrentTCB->uxPriority < uxPriority )
			{
				portYIELD_WITHIN_API(); //保存现成,然后选择下一个任务
			}
		}
	}

	return xReturn;
}

freertos 任务创建 xTaskCreate xTaskGenericCreate 源代码分析

进入临界区

#define taskENTER_CRITICAL()		portENTER_CRITICAL()
#define portENTER_CRITICAL()		vPortEnterCritical()
void vPortEnterCritical( void )
{
	portDISABLE_INTERRUPTS();
	uxCriticalNesting++;
}

#define portDISABLE_INTERRUPTS()	vPortSetInterruptMask() 关中断
__asm void vPortSetInterruptMask( void )
{
	PRESERVE8

	push { r0 }
	mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
	msr basepri, r0
	pop { r0 }
	bx r14
}
//通过basepri 屏蔽所有中断

任务链表初始化prvInitialiseTaskLists

static void prvInitialiseTaskLists( void )
{
unsigned portBASE_TYPE uxPriority;
 
for( uxPriority = ( unsigned portBASE_TYPE ) 0U; uxPriority < ( unsigned portBASE_TYPE )   configMAX_PRIORITIES; uxPriority++ )
{
vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) );//初始化就绪链表数组
}
 
vListInitialise( &xDelayedTaskList1 );//初始化延时链表1
vListInitialise( &xDelayedTaskList2 );//初始化延时列表2
vListInitialise( &xPendingReadyList );//初始化调度器挂起时就绪链表
 
#if ( INCLUDE_vTaskDelete == 1 )
{
vListInitialise( &xTasksWaitingTermination );//初始化被删除任务链表
}
#endif /* INCLUDE_vTaskDelete */
 
#if ( INCLUDE_vTaskSuspend == 1 )
{
vListInitialise( &xSuspendedTaskList );//初始化
}
#endif /* INCLUDE_vTaskSuspend */
 
/* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
using list2. */
pxDelayedTaskList = &xDelayedTaskList1;
pxOverflowDelayedTaskList = &xDelayedTaskList2;
}

链表初始化vListInitialise

void vListInitialise( xList * const pxList )
{
/* 列表结构包含了一个列项目 被用来标记一个列表的结尾
 To initialise the list the list end is inserted
作为唯一列的输入. */
pxList->pxIndex = ( xListItem * ) &( pxList->xListEnd );   /*lint !e826 !e740 The mini list structure is used as the list end to save RAM.  This is checked and valid. */
 
/* 列结束的值 是列表中可能的最高值 确保他能留在队列的最后*/
pxList->xListEnd.xItemValue = portMAX_DELAY;
 
/* 列尾的下一个和上一个指针指向他本身,当列是空时 */
pxList->xListEnd.pxNext = ( xListItem * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM.  This is checked and valid. */
pxList->xListEnd.pxPrevious = ( xListItem * ) &( pxList->xListEnd );/*lint !e826 !e740 The mini list structure is used as the list end to save RAM.  This is checked and valid. */
 
pxList->uxNumberOfItems = ( unsigned portBASE_TYPE ) 0U;
}

freertos 任务创建 xTaskCreate xTaskGenericCreate 源代码分析

任务切换函数

#define portYIELD_WITHIN_API portYIELD
#define portYIELD() vPortYieldFromISR()
void vPortYieldFromISR( void )  //请求中断函数
{
 /* Set a PendSV to request a context switch. */
 *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;
}

内存分配

static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer )
{
tskTCB *pxNewTCB;

	/* 分配TCB内存*/
	pxNewTCB = ( tskTCB * ) pvPortMalloc( sizeof( tskTCB ) );

	if( pxNewTCB != NULL )
	{
		/* 分配任务 所需要的内存*/
		pxNewTCB->pxStack = ( portSTACK_TYPE * ) pvPortMallocAligned( ( ( ( size_t )usStackDepth ) * sizeof( portSTACK_TYPE ) ), puxStackBuffer );

		if( pxNewTCB->pxStack == NULL )
		{
			/*任务内存分配失败,删掉新分配的TCB内存*/
			vPortFree( pxNewTCB );
			pxNewTCB = NULL;
		}
		else
		{
			/* 为了调试的*/
			memset( pxNewTCB->pxStack, tskSTACK_FILL_BYTE, usStackDepth * sizeof( portSTACK_TYPE ) );
		}
	}

	return pxNewTCB; //返回新创建的任务
}

任务初始化

static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth )
{
	#if configMAX_TASK_NAME_LEN > 1
	{
		/* Don't bring strncpy into the build unnecessarily. */
		strncpy( ( char * ) pxTCB->pcTaskName, ( const char * ) pcName, ( unsigned short ) configMAX_TASK_NAME_LEN );
	}
	#endif
	pxTCB->pcTaskName[ ( unsigned short ) configMAX_TASK_NAME_LEN - ( unsigned short ) 1 ] = ( signed char ) '\0';

	//确保任务优先级 不超过 定义的最大优先级 
	if( uxPriority >= configMAX_PRIORITIES )
	{
		uxPriority = configMAX_PRIORITIES - ( unsigned portBASE_TYPE ) 1U;
	}

	pxTCB->uxPriority = uxPriority;
	#if ( configUSE_MUTEXES == 1 )
	{
		pxTCB->uxBasePriority = uxPriority;
	}
	#endif
        
	vListInitialiseItem( &( pxTCB->xGenericListItem ) ); //初始化任务链表
	vListInitialiseItem( &( pxTCB->xEventListItem ) );   //初始化事件链表

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

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

	#if ( portCRITICAL_NESTING_IN_TCB == 1 )
	{
		pxTCB->uxCriticalNesting = ( unsigned portBASE_TYPE ) 0;
	}
	#endif

	#if ( configUSE_APPLICATION_TASK_TAG == 1 )
	{
		pxTCB->pxTaskTag = NULL;
	}
	#endif

	#if ( configGENERATE_RUN_TIME_STATS == 1 )
	{
		pxTCB->ulRunTimeCounter = 0UL;
	}
	#endif

	#if ( portUSING_MPU_WRAPPERS == 1 )
	{
		vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth );
	}
	#else
	{
		( void ) xRegions;
		( void ) usStackDepth;
	}
	#endif
}

cpu寄存器初始化

portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
{
	pxTopOfStack--; 
	*pxTopOfStack = portINITIAL_XPSR;	/* xPSR */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) pxCode;	/* PC */
	pxTopOfStack--;
	*pxTopOfStack = 0;	/* LR */
	pxTopOfStack -= 5;	/* R12, R3, R2 and R1. */
	*pxTopOfStack = ( portSTACK_TYPE ) pvParameters;	/* R0 */
	pxTopOfStack -= 8;	/* R11, R10, R9, R8, R7, R6, R5 and R4. */

	return pxTopOfStack;
}

添加任务定义

#define prvAddTaskToReadyQueue( pxTCB )																					\
	if( ( pxTCB )->uxPriority > uxTopReadyPriority )																	\
	{																													\
		uxTopReadyPriority = ( pxTCB )->uxPriority;																		\
	}																													\
	vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xGenericListItem ) )


你可能感兴趣的:(源代码分析,freertos任务创建,xTaskCreate)