关闭

深度解剖~ FreeRtos阅读笔记2 任务创建

322人阅读 评论(0) 收藏 举报
分类:

2.任务创建

开始源码阅读,这里我使用了TI cc3200 cortex m4的学习板,由TI提供移植后的freertos。

xTaskGenericCreate 函数用来创建一个新任务,在调度器启动前和启动后都可以创建。Freertos在调度器启动后至少会有一个任务在运行,即使开发者不去创建任务。源码中使用TCB结构体存放一个任务的所有信息,控制了某个TCB便是控制一个任务的运行状态。一个TCB将会根据需要在不同链表内重复插入和移除,比如等待被调度的任务插在readylist中,被taskDelay等函数睡过的任务则乖乖的放入xDelayedTaskList1或xDelayedTaskList2中,这两个链表有点意思,它们解决了systick变量溢出的问题,不过今天它不是主角,以后再细细说来。

先贴一些结构体图片(//亿图画的,绘画水平勉强能看。。。)

(TCB)

一个TCB中有两个链表节点,链表本身和节点并不完全相同,链表只保留了几个指针,其它元素根本使用不到,所以被叫做mini_list_item:


(LIST)


看清楚了任务及链表结构体组成,开始主流程分析。

(任务创建流程图)

2.1 prvAllocateTCBAndStack函数: 创建TCB 

Freertos在堆上分配一块TCB大小的空间,分配成功后便给任务分配一块任务栈空间,大小由开发者参数决定。注意栈分配时具有判断:

vPortMallocAligned( x,puxStackBuffer)(((puxStackBuffer)==NULL)?(pvPortMalloc((x))):(puxStackBuffer ))

表示开发者可以自己给出任务栈地址,也可以填入NULL选择让freertos分配(分配大小为栈深度*StackType_t)


2.2 prvInitialiseTCBVariables 、prvInitialiseTaskLists:负责初始化

栈指针对齐后便开始初始化该TCB上的一些链表节点prvInitialiseTCBVariables()。

如果是第一次创建任务还会初始化所有链表prvInitialiseTaskLists()。这些链表变量是task.c中的全局变量。链表中的一些值如MAX_DELAY一般会充当哨兵,当某个节点要按照升序或降序插入时查到该值freertos就认为这条链表已经遍历到尾部或头部了。

初始化后一些指针会做更改,还是贴一张图吧,有图有真相:



(链表及TCB初始化后)

不止这些,task.c中的全局变量还有很多,估计这些全局变量将会成为学习的难点。换我老师的话他肯定会说:恶心死人家了~。嗯 他是个男的。

2.3  pxPortInitialiseStack 执行”压栈

看源码时这里困扰了我好久,真是玩手游的时间都用上了,任务都没做!。还好葵花宝典上有答案,神书!引用M3权威指南上一句翻译:响应异常的第一个步骤是保存现场,硬件自动压栈,压栈后内存分布


再对比看下pxPortInitialiseStack源码:

对比下两者动作,这个函数是对任务栈进行了一些处理,并且是模仿异(中断)常发生时所产生的动作。为什么一定要模仿异常进行压栈,首先扯一下freertos任务调度工作的大致流程:

当一个任务在运行时,还有一个内部定时器(systick)在一直计数,它的计数值和时钟频率比值可以看成为时间片。时间片到,中断产生,中断里进行上下文切换也就是pxReadyTasksLists中的任务被依次调度。硬件进入中断时便会自动压栈,不需要我们处理。中断处理完成后到中断返回时硬件还会自动出栈,还原进入异常前的状态。进中断时压入的那些寄存器值都被一一出栈 如:PC、R0、等寄存器。这样pxPortInitialiseStack函数就好理解了,它先对新创建的任务进行手动压栈,还多包括了R4-R11,那么在调度中断结束后这些手动压入的值将被自动出栈,进而使新任务运行起来。

PC位置是传入的任务主程序句柄地址,也就是我们要任务执行的主要程序,LR(返回寄存器)的位置是prvTaskExitError函数地址,这个函数里是一个for死循环加错误信息打印,也就是一个任务永远不应从它的主程序中跳出,如果跳出则进入prvTaskExitError函数打印错误。一般任务句柄里都会用for(;;)把它写死永远循环执行,需要退出时要将该任务delete掉。


2.4插入链表

一个TCB创建并初始化完成后便开始插入readylist等待被调度。Readylist是一个数组,优先级最大数决定它的大小,一个TCB在插入时是按照优先级作为索引插入的,这里说TCB插入不太准确,应该是TCB上的链表节点插入链表。

举个栗子,第一个任务插入空链表时的状况:


看着有些凌乱的话再来张大意图:

如果此时又有一个相同优先级任务创建,链表变为:


简略图:

链表将节点依次连接,组成TCB链,调度器运行时会按照需要遍历链表进而控制任务。

链表头部都带有index元素,一开始它指向链表本身,所以我们上面创建的任务都像是在尾插,事实上调度器运行起来时新节点插入的位置由index决定。

图解:

调度开始后index开始遍历readylist,它指向第一个TCB时,第一个TCB得到cpu资源开始运行,变为:

注意红色线条变化,此时如果动态创建了一个优先级相同的任务TCB3,应该把它插在哪里?如果插在TCB后面那对于TCB2来说是不公平的,因为人家排队等待cpu的时间肯定比TCB3长,其实仔细考虑下插在链表头部或尾部都是不规律的,只有利用index。Freertos将其插在TCB前面,以保证是当前链表最后一个得到cpu资源的位置:


新TCB进入链表,任务创建流程就快结束了。在程序尾部有些优先级判断,如果创建的任务比当前运行的任务优先级要高则使能PendSV中断。如果调度器是停止的则直接更改当前TCB指针。


0
0
查看评论

深度解剖~ FreeRtos阅读笔记3 freertos调度器启动、中断优先级管理、中断优先级分组

3. freertos调度器启动、中断优先级管理、中断优先级分组 永远不要小看不起眼的东西,哪怕是短短的一行代码! 某些图片分辨率过大显示不清楚,保存到本地或点击放大会回复原状。 原本认为几分钟能搞定的vTaskStartScheduler函数结果一不小心弄到了中秋,还好有葵花宝典(CM3权威指南...
  • Yangquot
  • Yangquot
  • 2017-10-02 10:47
  • 245

深度解剖~ FreeRtos阅读笔记1

上帝不仅给了我一颗低频的cpu还送了个劣质的晶振,可悲可叹!无奈在家休养,不然的话晶振偷停我可就驾鹤西去了。。。不过这也是个好机会,在家靠着窗户晒着太阳,偶尔读读源码,都很好。就是工资没了~ 接连几个项目都使用了freertos,作为刚刚毕业一张白纸的我只能先去摸索一些api怎么去调用,需要填入哪...
  • Yangquot
  • Yangquot
  • 2017-09-27 16:59
  • 117

FreeRTOS 任务管理之任务创建

FreeRTOS 任务管理之任务创建任务概念任务:个人感觉就是将相关的一系列操作放在一个任务函数里来,跟线程差不多一个概念。任务创建在FreeRTOS中,任务创建是由任务创建函数来执行,任务创建函数原型如下:#define xTaskCreate( pvTaskCode, pcName, usSta...
  • jnu_fangzebin
  • jnu_fangzebin
  • 2016-06-28 21:07
  • 1138

FreeRtos新建任务不能运行

把#define configTOTAL_HEAP_SIZE 从15k改到48k就可以 ( ( size_t ) ( 48 * 1024 ) ) //15*1024 操作系统堆栈太小
  • hlt008
  • hlt008
  • 2017-08-12 08:15
  • 286

FreeRTOS系列第10篇---FreeRTOS任务创建和删除

在FreeRTOS移植到Cortex-M3硬件平台的文章中,我们已经见过任务创建API,但那篇文章的重点在于如何移植FreeRTOS,本文将重点放在任务的创建和删除API函数上面。      任务创建和删除API函数位于文件task.c中,需要包含task.h头文件。1...
  • zhzht19861011
  • zhzht19861011
  • 2015-12-21 14:43
  • 15828

FreeRTOS 任务调度 任务创建

@(嵌入式) 简述 任务状态 使用示例 数据结构 TCB 链表 任务创建 静态创建任务 动态创建任务 初始化任务控制块 栈初始化举例 插入就绪链表 参考 FreeRtos 简述FreeRTOS 的任务调度在 Source/include/task.c 中实现,包含了任务的创建、切换、挂起、延时和删...
  • qq_18150497
  • qq_18150497
  • 2016-10-13 00:30
  • 1804

FreeRTOS 任务创建和删除(静态)

#define configSUPPORT_STATIC_ALLOCATION 1 //打开静态方法StackType_t TaskStackBuffer[50]; //任务堆栈大小 StaticTask_t TaskTCBBuffer; //任务控制块大小StackTyp...
  • zhangxuechao_
  • zhangxuechao_
  • 2017-10-24 22:25
  • 158

FreeRTOS高级篇2---FreeRTOS任务创建分析

在FreeRTOS基础系列《FreeRTOS系列第10篇---FreeRTOS任务创建和删除》中介绍了任务创建API函数xTaskCreate(),我们这里先回顾一下这个函数的声明: BaseType_t xTaskCreate( ...
  • zhzht19861011
  • zhzht19861011
  • 2016-05-03 13:31
  • 14451

FreeRTOS 任务创建和删除(动态)

TaskHandle_t taskhandle; TaskHandle_t taskhandle1;void vTask(void *t) { int i = 0; while(1) { i++; if(i == 5) { ...
  • zhangxuechao_
  • zhangxuechao_
  • 2017-10-23 22:55
  • 115

FreeRTOS系列第9篇---FreeRTOS任务概述

1. 任务和协程(Co-routines)      应用程序可以使用任务也可以使用协程,或者两者混合使用,但是任务和协程使用不同的API函数,因此在任务和协程之间不能使用同一个队列或信号量传递数据。      通常情况下,协程仅用在资源非...
  • zhzht19861011
  • zhzht19861011
  • 2015-12-15 11:25
  • 13046
    个人资料
    • 访问:682次
    • 积分:38
    • 等级:
    • 排名:千里之外
    • 原创:0篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章分类
    文章存档