- 打卡等级:以坛为家I
- 打卡总天数:217
- 最近打卡:2024-11-15 09:12:27
荣誉版主
- 积分
- 2790
|
FreeRTOS for STC32G12K128内核代码解读(一)任务建立(上)
===后续文章见二楼的链接
本篇核心内容
源码工程为 官网下载的 FreeRTOS 库函数版本
一 任务建立函数参数
这就是今天的主角
任务建立函数
跳进去 函数定义
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
const configSTACK_DEPTH_TYPE usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask )
解释一下这些参数
参数1pxTaskCode 任务函数名
参数2pcName 任务名字 (就是个字符串,别和参数1搞混)
参数3usStackDepth(堆) 栈深度
参数4pvParameters 任务函数参数
参数5uxPriority 任务优先级
参数6pxCreatedTask 任务句柄(这个是传出来的,不是传进去的)
二 TCB 任务控制块 结构
函数内 建了一个TCB (任务控制块) 的指针
我们跳转,查看这个数据结构的内容
条件编译我们先跳过
需要时再看
解释一下这个数据结构的内容
看不懂没关系,后面的代码会 给结构体赋值的
三 TCB 申请(堆)栈空间
回到 函数体
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
上面这行,给新的TCB 分配了一块空间
如何分配的 有点长 暂时先不看 -属于内存管理的内容了
继续阅读
753 行 pxNewTCB->pxStack = 给TCB 的栈 分配了一块(堆)栈空间
四 初始化新任务
如果 (堆)栈申请成功了
调用 prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL );
初始化新任务,看到 这堆参数 基本能猜到 要给TCB 赋值了
跳转到该函数
876行 pxTopOfStack = pxNewTCB->pxStack;
先配置一下(堆)栈顶,栈顶指向起始栈
条件编译先跳过
888行 开始 if( pcName != NULL ) 判断一下名字是否为空
非空就赋值给TCB的pcTaskName[]任务名字 pxNewTCB->pcTaskName[ x ] = pcName[ x ];
938行 vListInitialiseItem( &( pxNewTCB->xStateListItem ) );
vListInitialiseItem( &( pxNewTCB->xEventListItem ) );
这两行初始化了 状态链表 和事件链表
之前这两个链表没有展开
现在展开看一下
常见的双向链表
前三个是 项值, 前项与后项指针
pvOwner 链表持有者指针(TCB)
pxContainer 项所在的链表指针(如果有)
看看初始化函数
pxItem->pxContainer = NULL;
把pxContainer 项所在的链表指针设为空
返回到 prvInitialiseNewTask()
调查宏定义 发现这几行是给 链表项/持有者赋值
#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )
#define listSET_LIST_ITEM_VALUE( pxListItem, xValue ) ( ( pxListItem )->xItemValue = ( xValue ) )
listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB );
/* Event lists are always in priority order. */
listSET_LIST_ITEM_VALUE( &( pxNewTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
listSET_LIST_ITEM_OWNER( &( pxNewTCB->xEventListItem ), pxNewTCB );
即:
给两个链表的pvOwner 赋值为 pxNewTCB 我们刚刚建立的新TCB任务控制块
给事件链表xEventListItem 的项值xItemValue 赋值为 uxPriority 优先级
跳过中间的条件编译
1052行 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
初始化 (堆)栈
看第76行:
ulAddress = ( uint32_t ) pxCode;
*pxTopOfStack = ( StackType_t ) ( ulAddress >> 16 ); /* PC[23:16] */
pxTopOfStack++;
*pxTopOfStack = ( StackType_t ) ( ulAddress >> 8 ); /* PC[15:8] */
pxTopOfStack++;
*pxTopOfStack = ( StackType_t ) ( ulAddress ); /* PC[7:0] */
把函数名(地址) 先存到(堆)栈
c251地址总线是24位
这里函数的地址 也是24位
下面补充两个关于函数调用的基础知识 (知道的可以跳过)
1.pc指针
这里解释一下 pc指针 就是指向当前所运行代码 的地址
我们调用函数 =》 将pc指针 指向被调函数的地址
下图是调用函数时PC 指针的值 与函数地址
2. 栈(保存现场)
大家都知道 cpu运行时离不开寄存器
而调用函数时,这些寄存器的值怎么办
这些值要保存到内存中,这个内存空间叫栈
继续看代码
PSW DPTR DR28~DR4 的(堆)栈空间初始化
继续
这几行把 函数的参数存起来了
将会占用DR0 这个四字节的寄存器
return pxTopOfStack;
返回栈顶,该函数结束
回到xTaskCreate()了
五 添加任务
第805行
prvAddNewTaskToReadyList( pxNewTCB );
添加任务到就绪链表(数组)函数
跳进去
1077行 uxCurrentNumberOfTasks++;
当前任务数+1
pxCurrentTCB = pxNewTCB;
如果新任务 不是空的
将新任务设置为 当前任务
if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )
如果第一个任务
prvInitialiseTaskLists();
初始化任务链表
跳进去
for( uxPriority = ( UBaseType_t ) 0U; uxPriority < ( UBaseType_t ) configMAX_PRIORITIES; uxPriority++ )
{
vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) );
}
vListInitialise( &xDelayedTaskList1 );
vListInitialise( &xDelayedTaskList2 );
vListInitialise( &xPendingReadyList );
内容有点多
分两期吧
|
1
喜欢他/她就送朵鲜花吧,赠人玫瑰,手有余香!
-
+2
楼主威武~
|