赞
踩
1.函数指针,即任务函数的名称
2.任务名称是字符创
3.栈的大小
4.参数(放在R0寄存器里)
5.任务的优先级
6.任务句柄(传入的是指针)
Freertos 中portSTACK_GROWTH>0表明栈是向上增长的,arm是向下增长的,所以进入else
pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) );
分配栈的空间
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );//指向低地址
分配任务控制块的空间
pxNewTCB->pxStack = pxStack;
任务控制块的pxStack指向分配的空间
分配栈的大小,并将起始地址存入TCB.
这一点和一个结构体中一个指针指向一个空间时,需要先分配是一样的。
给任务控制块分配空间(回传给任务句柄) 。
前面分配的栈空间,
初始化任务。
1.函数指针
2.函数名称。//字符串
3.栈大小
4.任务优先级
5.任务句柄
6.任务控制块
7.
pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); // 进行字节对齐,2位对齐,就是将最后一位清零,8位对齐就是将末七位清零。
获取栈顶地址,pxTopOfStack的地址为栈的高地址,随着入栈而减小,指向最后入栈的,所以也就是未入栈时的高地址
pxStack为栈的起始地址,低地址,地址是不变的,一般用于栈溢出检测(没看到在哪有检测环节)。
TCB记录任务的优先级
初始化TCB的两个链表
刚创建的任务还没有放入就绪链表,Container(用于指定该列表项属于哪一个列表)指向就绪链表(等)
展开形式
#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )
能够从任务控制块中得信息(我也不懂),设置该任务控制块的列表项属于该任务控制块
事件链表是根据优先级设置链表项的值的,优先级越高(号大的优先级高),值越大。
(应该是在插入列表项的时候用到)
任务句柄会获得任务控制块,这样就可以通过任务句柄控制任务
新创建的任务默认是就绪态
目前所有的任务(初始值为0)
当前是否有任务运行,CurrentTCB是全局变量。
假设没有。
这个新任务就是当前任务
如果当前任务是第一个任务,执行下面的初始化列表。
prvInitialiseTaskLists();//见解析一
任务总量加一(尚不明白和当前任务数量的区别)
加入就绪链表
是加在就绪链表最后的。
就绪链表根据有限级分成几个
会指明任务状态(就绪,阻塞等)
每一个链表都有链表指针,指示当前的链表的第一个列表项。(此时的Index就是一个列表项)
根据传入的指针,pxList就是就绪链表。
将任务的状态链表插入当前链表项的后面。(就是链表的最后)。
pxIndex->pxPrevious->pxNext = pxNewListItem;
pxIndex->pxPrevious = pxNewListItem;
/* Remember which list the item is in. */
pxNewListItem->pvContainer = ( void * ) pxList;
解析:初始化栈。
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack,栈顶
pxTaskCode,函数指针
pvParameters );参数
1264_FreeRTOS任务的初始化以及堆栈初始化处理分析_堆栈模型的初始化-CSDN博客
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{
/* Simulate the stack frame as it would be created by a context switch
interrupt. */
//创建的任务可能不会被立即执行,所以需要模拟任务是被中断了的,所以需要将中断需要入栈的寄存器入栈,来模拟中断
pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */
*pxTopOfStack = portINITIAL_XPSR; /* xPSR */
pxTopOfStack--;
*pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; /* PC */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) prvTaskExitError; /* LR */
pxTopOfStack -= 5; /* R12, R3, R2 and R1. */
*pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */
return pxTopOfStack;
}
列表结构体
typedef struct xLIST
{
listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
configLIST_VOLATILE UBaseType_t uxNumberOfItems;
ListItem_t * configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */
MiniListItem_t xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */
listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
} List_t;
见解析一:static void prvInitialiseTaskLists( void )
{
UBaseType_t uxPriority;
for( uxPriority = ( UBaseType_t ) 0U; uxPriority < ( UBaseType_t ) configMAX_PRIORITIES; uxPriority++ )
{
vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) );//pxReadyTasksLists[ uxPriority ]是一个列表结构体数组,根据优先级不同,有不同的列表。关于vListInitialise()见解析二
}
vListInitialise( &xDelayedTaskList1 );//延时列表
vListInitialise( &xDelayedTaskList2 );//延时列表溢出时保存
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;//这是一个列表指针,均为全局变量
}
解析二:
void vListInitialise( List_t * const pxList )
{
/* The list structure contains a list item which is used to mark the
end of the list. To initialise the list the list end is inserted
as the only list entry. */
pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */(list end 代表列表尾部)pxIndex是用来遍历列表的。列表中的 pxIndex 成员变量是用来遍历列表的, pxIndex 所指向的列表项就是要遍历的开始列表项,
/* The list end value is the highest possible value in the list to
ensure it remains at the end of the list. */
pxList->xListEnd.xItemValue = portMAX_DELAY;(列表项插入时,根据值来排序。值大的在后)
/* The list end next and previous pointers point to itself so we know
when the list is empty. */
空列表时的指向
pxList->xListEnd.pxNext = ( ListItem_t * ) &( 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 = ( ListItem_t * ) &( 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 = ( UBaseType_t ) 0U;
/* Write known values into the list if
configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
}
上方的初始归结为一个图表。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。