FreeRTOS内核学习笔记记录(二)——任务数据结构与任务创建-基于CortexM3

FreeRTOS任务

1、任务控制块TCB

任务控制块 一种基于ListItem链表结点的数据结构

typedef struct tskTaskControlBlock
{
    /*栈顶指针*/
	volatile StackType_t	*pxTopOfStack;	
    /*配置 内存保护MPU*/
	#if ( portUSING_MPU_WRAPPERS == 1 )
		xMPU_SETTINGS	xMPUSettings;		/*< The MPU settings are defined as part of the port layer.  THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */
	#endif
    /*任务管理的任务结点*/
	ListItem_t			xStateListItem;	
	/*事件管理的事件结点*/
	ListItem_t			xEventListItem;		
	/*任务优先级*/
	UBaseType_t			uxPriority;			
	/*任务堆栈指针 (栈起始地址)*/
	StackType_t			*pxStack;			
	/*任务名称*/
	char				pcTaskName[ configMAX_TASK_NAME_LEN ];
    /*栈生长方向 对于CortexM3内核栈是向下生长 的满栈模型
    即栈从高地址向低地址生长 portSTACK_GROWTH配置应<0
    对于CortexM3没有*pxEndofStack尾指针的定义
*/
	#if ( portSTACK_GROWTH > 0 )
		StackType_t		*pxEndOfStack;		
	#endif
    /*临界区 TCB嵌套 */
	#if ( portCRITICAL_NESTING_IN_TCB == 1 )
		UBaseType_t		uxCriticalNesting;	/*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */
	#endif
    /*启用系统性能跟踪 启用此宏用于调试*/
	#if ( configUSE_TRACE_FACILITY == 1 )
		UBaseType_t		uxTCBNumber;		/*< Stores a number that increments each time a TCB is created.  It allows debuggers to determine when a task has been deleted and then recreated. */
		UBaseType_t		uxTaskNumber;		/*< Stores a number specifically for use by third party trace code. */
	#endif
    /*使用互斥*/
	#if ( configUSE_MUTEXES == 1 )
		UBaseType_t		uxBasePriority;		
		UBaseType_t		uxMutexesHeld;
	#endif
    /*使用任务应用标志*/
	#if ( configUSE_APPLICATION_TASK_TAG == 1 )
		TaskHookFunction_t pxTaskTag;
	#endif
    /*启用线程本地指针*/
	#if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
		void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
	#endif
    /*启用实时统计*/
	#if( configGENERATE_RUN_TIME_STATS == 1 )
		uint32_t		ulRunTimeCounter;	
	#endif
    /*使用一个新库 供开发者自己添加*/
	#if ( configUSE_NEWLIB_REENTRANT == 1 )
		struct	_reent xNewLib_reent;
	#endif
    /*开启任务通知 一种内核对象*/
	#if( configUSE_TASK_NOTIFICATIONS == 1 )
		volatile uint32_t ulNotifiedValue;
		volatile uint8_t ucNotifyState;
	#endif
    /*TCB的一个成员用于记录是否分配内存
堆栈和/或TCB是静态或动态分配
    tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE仅当它可能用于
使用静态或动态分配RAM创建的任务。请注意
如果portUSING_MPU_WRAPPERS为1,则可以使用它创建受保护任务
静态分配的堆栈和动态分配的TCB*/
	#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
		uint8_t	ucStaticallyAllocated; 		/*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */
	#endif
     /*是否取消任务延时 一般不启用 为0*/
	#if( INCLUDE_xTaskAbortDelay == 1 )
		uint8_t ucDelayAborted;
	#endif

} tskTCB;

在这里插入图片描述
任务控制块实际是基于list数据结构的一块内存,基本成员+#define可配置成员组成

2、任务创建xTaskCreate(…)

动态创建函数
xTaskCreate
(	
/*执行任务的函数 实际任务入口*/
TaskFunction_t pxTaskCode,
/*任务名称*/
const char * const pcName,
/*任务栈深度*/
const uint16_t usStackDepth,
/*任务形参*/
void * const pvParameters,
/*任务优先级*/
UBaseType_t uxPriority,
/*任务控制块指针*/
TaskHandle_t * const pxCreatedTask 
) 

动态创建任务函数流程
在这里插入图片描述
分配任务堆栈、控制块堆栈;动态内存分配用的heap4模型-小内存分配模型;
初始化任务并将任务添加至就绪列表

BaseType_t xTaskCreate(	TaskFunction_t pxTaskCode,/*任务函数 真正的任务入口*/
							const char * const pcName,/*任务名称*/
							const uint16_t usStackDepth,/*任务堆栈深度*4Bytes*/
							void * const pvParameters,/*任务形参*/
							UBaseType_t uxPriority,/*任务优先级*/
							TaskHandle_t * const pxCreatedTask )/*任务控制块指针*/
	{
	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 /* CortexM3内核使用的是向下生长满栈模型 直接跳转到这里 */
		{
		StackType_t *pxStack;
		/*动态内存分配任务堆栈 大小为usStackDepth*4Bytes 
		动态内存分配有heap2和heap4模型 其中 heap2模型会产生内存小碎片 heap4模型会合并一些动态内存碎片
*/
			pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); 

			if( pxStack != NULL )
			{  /*任务栈初始化完成后再初始化TCB控制块,与向上生长堆栈模型相反,向上生长会先分配TCB控制块,再分配任务堆栈*/
				pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); /
                /*TCB分配成功*/
				if( pxNewTCB != NULL )
				{
					/*保存任务堆栈的位置到TCB的堆栈指针*/
					pxNewTCB->pxStack = pxStack;
				}
				else
				{
					/*否则释放任务堆栈*/
					vPortFree( pxStack );
				}
			}
			else
			{
				pxNewTCB = NULL;
			}
		}
		#endif 
		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 );
			/*添加任务到就绪列表*/
			prvAddNewTaskToReadyList( pxNewTCB );
			xReturn = pdPASS;
		}
		else
		{
			xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
		}

		return xReturn;
	}

在这里插入图片描述
这里借鉴了别人的图片;即要保证TCB在task[0][0]位置,需要在堆栈初始化时,对于向下生长模型,先从task[0][TASK_STK_SIZE-1]压入任务栈,然后再压入TCB;对于向上生长堆栈模型,需要先压入TCB,再压入任务堆栈。

prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL );
/*初始化任务*/

```c
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;
    /*启用MPU保护*/
	#if( portUSING_MPU_WRAPPERS == 1 )
		/* Should the task be created in privileged mode? */
		BaseType_t xRunPrivileged;
		if( ( uxPriority & portPRIVILEGE_BIT ) != 0U )
		{
			xRunPrivileged = pdTRUE;
		}
		else
		{
			xRunPrivileged = pdFALSE;
		}
		uxPriority &= ~portPRIVILEGE_BIT;
	#endif /* portUSING_MPU_WRAPPERS == 1 */
    /*配置栈溢出检测*/
	#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
	{
		/* 填充已知的值到堆栈内再通过调试去读出 从而检查堆栈是否溢出 */
		( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) ulStackDepth * sizeof( StackType_t ) );
	}
	#endif 
   /*确定pxTopofStack的位置=TCB的任务堆栈位置+堆栈深度即栈顶指针到了TCB的位置*/
	pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
	/*栈指针8字节对其 cortexm3也是8字节对齐的*/
		pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); 
	/**/	
	configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
    /*保存任务名称*/
	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';
	/*优先级限制不能超过最大优先级*/
	if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
	{
		uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}
	pxNewTCB->uxPriority = uxPriority;
	/*启用RTOS的互斥*/
	#if ( configUSE_MUTEXES == 1 )
	{
		pxNewTCB->uxBasePriority = uxPriority;
		pxNewTCB->uxMutexesHeld = 0;
	}
	#endif /* configUSE_MUTEXES */
    /*初始化任务链表结点和事件列表结点 让其pvContainer指向NULL*/
	vListInitialiseItem( &( pxNewTCB->xStateListItem ) );
	vListInitialiseItem( &( pxNewTCB->xEventListItem ) );
    /*设置任务链表结点归属于此TCB*/
	listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB );
	/*设置事件链表结点内的排序值*/
	listSET_LIST_ITEM_VALUE( &( pxNewTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority ); 
	/*设置事件链表结点归属于此TCB*/
	listSET_LIST_ITEM_OWNER( &( pxNewTCB->xEventListItem ), pxNewTCB );
	#if ( portCRITICAL_NESTING_IN_TCB == 1 )
	{
		pxNewTCB->uxCriticalNesting = ( UBaseType_t ) 0U;
	}
	#endif /* portCRITICAL_NESTING_IN_TCB */
	#if ( configUSE_APPLICATION_TASK_TAG == 1 )
	{
		pxNewTCB->pxTaskTag = NULL;
	}
	#endif /* configUSE_APPLICATION_TASK_TAG */
	#if ( configGENERATE_RUN_TIME_STATS == 1 )
	{
		pxNewTCB->ulRunTimeCounter = 0UL;
	}
	#endif /* configGENERATE_RUN_TIME_STATS */
	#if ( portUSING_MPU_WRAPPERS == 1 )
	{
		vPortStoreTaskMPUSettings( &( pxNewTCB->xMPUSettings ), xRegions, pxNewTCB->pxStack, ulStackDepth );
	}
	#else
	{
		/* Avoid compiler warning about unreferenced parameter. */
		( void ) xRegions;
	}
	#endif
	#if( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 )
	{
		for( x = 0; x < ( UBaseType_t ) configNUM_THREAD_LOCAL_STORAGE_POINTERS; x++ )
		{
			pxNewTCB->pvThreadLocalStoragePointers[ x ] = NULL;
		}
	}
	#endif
	#if ( configUSE_TASK_NOTIFICATIONS == 1 )
	{
		pxNewTCB->ulNotifiedValue = 0;
		pxNewTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
	}
	#endif
	#if ( configUSE_NEWLIB_REENTRANT == 1 )
	{
		/* Initialise this task's Newlib reent structure. */
		_REENT_INIT_PTR( ( &( pxNewTCB->xNewLib_reent ) ) );
	}
	#endif
	#if( INCLUDE_xTaskAbortDelay == 1 )
	{
		pxNewTCB->ucDelayAborted = pdFALSE;
	}
	#endif
	#if( portUSING_MPU_WRAPPERS == 1 )
	{
		pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
	}
	#else /* portUSING_MPU_WRAPPERS */
	{
	   /*最重要的一步 初始化任务栈 与cortexm3内核相关 作用是将CPU寄存器压入任务堆栈*/
		pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
	}
	#endif /* portUSING_MPU_WRAPPERS */
	if( ( void * ) pxCreatedTask != NULL )
	{
		/*成功创建TCB后 返回NewTCB地址*/
		*pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}
}

``
在prvInitialiseNewTask最后需要调用pxPortInitialiseStack,将任务相关信息压入CPU的寄存器内,PC指针指向pxTaskCode也将被保存;当需要使用时会调回到pxTaskCode进入此任务。

StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{
	pxTopOfStack--; /*已知pxTopofStack是已经指向TCB的指针*/
	*pxTopOfStack = portINITIAL_XPSR;	/* xPSR 的 bit24 必须置 1,即 0x01000000 */
	pxTopOfStack--;
	/*保存任务的入口地址到PC*/
	*pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK;	
	pxTopOfStack--;
	/*LR链接了一个错误处理入口*/
	*pxTopOfStack = ( StackType_t ) prvTaskExitError;	
    /*默认初始化R12 R3 R2 R1 这是CPU自动行为*/
	pxTopOfStack -= 5;	/* R12, R3, R2 and R1. */
	*pxTopOfStack = ( StackType_t ) pvParameters;	/* R0 */
	/*手动压入剩余寄存器*/
	pxTopOfStack -= 8;	/* R11, R10, R9, R8, R7, R6, R5 and R4. */
    /*最后的是R4也是pxTopofStack的位置*/
	return pxTopOfStack;
}

理解为栈顶压入了CPU寄存器的相关内容,用于能恢复现场。从栈顶开始到栈底依次是CPU寄存器 TCB 任务堆栈 所以R4的下一个位置时TCB的首地址。

static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
{
	taskENTER_CRITICAL();
	{
		uxCurrentNumberOfTasks++;/*一个全局变量 当任务创建成功后 会自加*/
		/*当pxCurrentTCB是空表明这是第一个被创建的任务*/
		if( pxCurrentTCB == NULL )/*pxCurrentTCB也是一个全局的TCB指针*/
		{
			pxCurrentTCB = pxNewTCB;/*全局变量指针指向这个TCB*/
			if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )/*在这之前pxCurrentTCB都为空 所以只有一个任务*/
			{
				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++;//任务总数++
		#if ( configUSE_TRACE_FACILITY == 1 )
		{
			pxNewTCB->uxTCBNumber = uxTaskNumber;
		}
		#endif /* configUSE_TRACE_FACILITY */
		traceTASK_CREATE( pxNewTCB );
		/*加入就绪列表*/
		prvAddTaskToReadyList( pxNewTCB );
		portSETUP_TCB( pxNewTCB );
	}
	taskEXIT_CRITICAL();

	if( xSchedulerRunning != pdFALSE )/*调度器已经启用*/
	{
		/* If the created task is of a higher priority than the current task
		then it should run now. */
		if( pxCurrentTCB->uxPriority < pxNewTCB->uxPriority )
		{
			taskYIELD_IF_USING_PREEMPTION();//任务调度
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}
}

将任务的TCB添加到就绪列表去管理,就绪列表是List_t的根节点数据结构,允许有多少个优先级则有多少个这样的根节点数据结构,将ListItem的TCB链表数据结构挂载到就绪列表中实现任务调度。

xTaskCreate任务创建的函数框架

在这里插入图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FreeRTOS 内核结构主要由以下几部分组成: 1. 任务管理器:FreeRTOS 内核中最重要的部分是任务管理器。任务FreeRTOS 中最基本的执行单元,任务有自己的堆栈空间、优先级和状态等属性。任务管理器负责管理任务创建、删除、切换和调度等操作,以及处理任务之间的通信和同步。 2. 调度器:调度器是 FreeRTOS 内核中的核心组件,它负责决定哪个任务在当前时刻应该运行。调度器可以根据任务的优先级、时间片轮转等算法进行任务调度,以确保系统的可响应性和实时性。 3. 信号量和互斥量:FreeRTOS 提供了信号量和互斥量等同步机制,用于实现任务之间的通信和同步。信号量用于控制任务对共享资源的访问,互斥量用于确保同时只有一个任务能够访问共享资源。 4. 队列和消息传递:FreeRTOS 提供了队列和消息传递机制,用于实现任务之间的数据传递和通信。任务可以通过向队列中发送消息的方式来与其他任务进行通信,也可以通过接收队列中的消息来等待其他任务的响应。 5. 定时器服务:FreeRTOS 提供了定时器服务,可以用于实现定时任务、延时操作等。定时器服务可以在任务创建和启动定时器,定时器到期后会触发回调函数,执行相应的操作。 总之,FreeRTOS 内核结构是由任务管理器、调度器、同步机制、通信机制和定时器服务等组件构成的,这些组件相互协作,共同实现了 FreeRTOS 的多任务调度和实时性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值