在嵌入式领域中,嵌入式实时作业系统正得到越来越广泛的套用。採用嵌入式实时作业系统(RTOS)可以更合理、更有效地利用CPU的资源,简化套用软体的设计,缩短系统开发时间,更好地保证系统的实时性和可靠性。
基本介绍
- 外文名:FreeRTOS
- 本质:小型实时作业系统核心
- 功能包括:任务管理、时间管理、记忆体管理
- 特点:源码公开、可移植、可裁减
简介
FreeRTOS是一个迷你的实时作业系统核心。作为一个轻量级的作业系统,功能包括:任务管理、时间管理、信号量、讯息伫列、记忆体管理、记录功能、软体定时器、协程等,可基本满足较小系统的需要。
由于RTOS需占用一定的系统资源(尤其是RAM资源),只有μC/OS-II、embOS、salvo、FreeRTOS等少数实时作业系统能在小RAM单片机上运行。相对μC/OS-II、embOS等商业作业系统,FreeRTOS作业系统是完全免费的作业系统,具有源码公开、可移植、可裁减、调度策略灵活的特点,可以方便地移植到各种单片机上运行,其最新版本为10.1.0版。
功能和特点
用户可配置核心功能
多平台的支持
提供一个高层次的信任代码的完整性
目标代码小,简单易用
遵循MISRA-C标準的编程规范
强大的执行跟蹤功能
堆叠溢出检测
没有限制的任务数量
没有限制的任务优先权
多个任务可以分配相同的优先权
伫列,二进制信号量,计数信号灯和递归通信和同步的任务
优先权继承
免费开源的原始码
原理与实现
任务调度机制是嵌入式实时作业系统的一个重要概念,也是其核心技术。对于可剥夺型核心,优先权高的任务一旦就绪就能剥夺优先权较低任务的CPU使用权,提高了系统的实时回响能力。不同于μC/OS-II,FreeRTOS对系统任务的数量没有限制,既支持优先权调度算法也支持轮换调度算法,因此FreeRTOS採用双向鍊表而不是採用查任务就绪表的方法来进行任务调度。系统定义的鍊表和鍊表节点数据结构如下所示:
//定义鍊表结构
typedef struct xLIST{
unsigned portSHORPT usNumberOfItems; //usNumberOfItems为鍊表的长度,为0表示鍊表为空
volatile xListItem * pxHead; //pxHead为鍊表的头指针
volatile xListItem * pxIndex; //pxIndex指向鍊表当前结点的指针
volatile xListItem xListEnd; //xListEnd为鍊表尾结点
}xList;
//定义鍊表结点的结构
struct xLIST_ITEM {
port Tick type; //port Tick Type为时针节拍数据类型,
xItem Value; //xItem Value的值用于实现时间管理,可根据需要选择为16位或32位
volatile struct xLIST_ITEM * pxNext; //指向鍊表的前一个结点
void * pvOwner; //指向此鍊表结点所在的任务控制块
void * pvContainer; //指向此鍊表结点所在的鍊表
};
FreeRTOS中每个任务对应于一个任务控制块(TCB),其定义如下所示:
typedef struct tskTaskControlBlock {
portSTACK_TYPE * pxTopOfStack; //指向任务堆叠结束处
portSTACK_TYPE * pxStack; //指向任务堆叠起始处
unsigned portSHORT usStackDepth; //定义堆叠深度
signed portCHAR pcTaskName[tskMAX_TASK_NAME_LEN]; //任务名称
unsigned portCHAR ucPriority; //任务优先权
xListItem xGenericListItem; //用于把TCB插入就绪鍊表或等待鍊表
xListItem xEventListItem; //用于把TCB插入事件鍊表(如讯息伫列)
unsigned portCHAR ucTCBNumber; //用于记录功能
}tskTCB;
FreeRTOS定义就绪任务鍊表数组为xList pxReady—TasksLists[portMAX_PRIORITIES]。其中portMAX_PRIORITIES为系统定义的最大优先权。若想使优先权为n的任务进入就绪态,需要把此任务对应的TCB中的结点xGenericListltem插入到鍊表pxReadyTasksLiStS[n]中,还要把xGenericListItem中的pvContainer指向pxReadyTasksLists[n]方可实现。
当进行任务调度时,调度算法首先实现优先权调度。系统按照优先权从高到低的顺序从就绪任务鍊表数组中寻找usNumberOfItems第一个不为0的优先权,此优先权即为当前最高就绪优先权,据此实现优先权调度。若此优先权下只有一个就绪任务,则此就绪任务进入运行态;若此优先权下有多个就绪任务,则需採用轮换调度算法实现多任务轮流执行。
若在优先权n下执行轮换调度算法,系统先通过执行
(pxReadyTasksLists[n])→pxIndex=(pxReadyTasks-Lists[n])→pxlndex→pxNext语句得到当前结点所指向的下一个结点,再通过此结点的pvOwner指针得到对应的任务控制块,最后使此任务控制块对应的任务进入运行态。由此可见,在FreeRTOS中,相同优先权任务之间的切换时间为一个时钟节拍周期。
以图l为例,设系统的最大任务数为pottMAX_PRIORITIES,在某一时刻进行任务调度时,得到pxReadyTasksLists.usNumberOfItems=O(i=2...portMAX_PRIORITIES)以及pxReadyTasksLists[1]。usNumberOfItems=3。由此核心可知当前最高就绪优先权为l,且此优先权下已有三个任务已进入就绪态.由于最高就绪优先权下有多个就绪任务,系统需执行轮换调度
算法实现任务切换;通过指针pxlndex可知任务l为当前任务,而任务l的pxNext结点指向任务2,因此系统把pxIndex指向任务2并执行任务2来实现任务调度。当下一个时钟节拍到来时,若最高就绪优先权仍为1,由图l可见,系统会把pxIndex指向任务3并执行任务3。
为了加快任务调度的速度,FrecRTOS通过变数ucTopReadyPriotity跟蹤当前就绪的最高优先权。当把一个任务加入就绪鍊表时,如果此任务的优先权高于ucTopReadyPriority,则把这个任务的优先权赋予ucTopReadyPriority。这样当进行优先权调度时,调度算法不是从portMAX_PRIORITIES而是从ucTopReady-Priority开始搜寻。这就加快了搜寻的速度,同时缩短了核心关断时间。
2.2任务管理的实现 实现多个任务的有效管理是作业系统的主要功能。FreeRTOS下可实现创建任务、删除任务、挂起任务、恢复任务、设定任务优先权、获得任务相关信息等功能。下面主要讨论FreeRTOS下任务创建和任务删除的实现。当调用sTaskCreate()函式创建一个新的任务时,FreeRTOS首先为新任务分配所需的记忆体。若记忆体分配成功,则初始化任务控制块的任务名称、堆叠深度和任务优先权,然后根据堆叠的增长方向初始化任务控制块的堆叠。接着,FreeRTOS把当前创建的任务加入到就绪任务鍊表。若当前此任务的优先权为最高,则把此优先权赋值给变数ucTopReadyPriorlty(其作用见2.1节)。若任务调度程式已经运行且当前创建的任务优先权为最高,则进行任务切换.
不同于μC/OS—II,FreeRTOS下任务删除分两步进行。当用户调用vTaskDelete()函式后,执行任务删除的第一步:FreeRTOS先把要删除的任务从就绪任务鍊表和事件等待鍊表中删除,然后把此任务添加到任务删除鍊表,若删除的任务是当前运行任务,系统就执行任务调度函式,至此完成任务删除的第一步。当系统空闲任务即prvldleTask()函式运行时,若发现任务删除鍊表中有等待删除的任务,则进行任务删除的第二步,即释放该任务占用的记忆体空间,并把该任务从任务删除鍊表中删除,这样才彻底删除了这个任务。值得注意的是,在FreeRTOS中,当系统被配置为不可剥夺核心时,空闲任务还有实现各个任务切换的功能。
通过比较μC/OS-II和FreeRTOS的具体代码发现,採用两步删除的策略有利于减少核心关断时间,减少任务删除函式的执行时间,尤其是当删除多个任务的时候。
2.3时间管理的实现 FreeRTOS提供的典型时间管理函式是vTaskDelay(),调用此函式可以实现将任务延时一段特定时间的功能。在FreeRT0S中,若一个任务要延时xTicksToDelay个时钟节拍,系统核心会把当前系统已运行的时钟节拍总数(定义为xTickCount,32位长度)加上xTicksToDelay得到任务下次唤醒时的时钟节拍数xTimeToWake。然后,核心把此任务的任务控制块从就绪鍊表中删除,把xTim
eToWake作为结点值赋予任务的xItemValue,再根据xTimeToWake的值把任务控制块按照顺序插入不同的鍊表。若xTimeToWake>xTickCount,即计算中没有出现溢出,核心把任务控制块插入到pxDelayedTaskList鍊表;若xTimeToWake 每发生一个时钟节拍,核心就会把当前的xTick-Count加1。若xTickCount的结果为0,即发生溢出,核心会把pxOverflowDelayedTaskList作为当前鍊表;否则,核心把pxDelaycdTaskList作为当前鍊表。核心依次比较xTickCotlrtt和鍊表各个结点的xTimcToWake。若xTick-Count等于或大于xTimeToWake,说明延时时间已到,应该把任务从等待鍊表中删除,加入就绪鍊表。
由此可见,不同于μC/OS—II,FreeRTOS採用“加”的方式实现时间管理。其优点是时间节拍函式的执行时间与任务数量基本无关,而μC/OS—II的OSTimcTick()的执行时间正比于应用程式中建立的任务数。因此当任务较多时,FreeRTOS採用的时间管理方式能有效加快时钟节拍中断程式的执行速度。
2.4记忆体分配策略 每当任务、伫列和信号量创建的时候,FreeRTOS要求分配一定的RAM。虽然採用malloc()和free()函式可以实现申请和释放记忆体的功能,但这两个函式存在以下缺点:并不是在所有的嵌入式系统中都可用,要占用不定的程式空间,可重入性欠缺以及执行时间具有不可确定性。为此,除了可採用malloc()和free()函式外,FreeRTOS还提供了另外两种记忆体分配的策略,用户可以根据实际需要选择不同的记忆体分配策略。
第1种方法是,按照需求记忆体的大小简单地把一大块记忆体分割为若干小块,每个小块的大小对应于所需求记忆体的大小。这样做的好处是比较简单,执行时间可严格确定,适用于任务和伫列全部创建完毕后再进行核心调度的系统;这样做的缺点是,由于记忆体不能有效释放,系统运行时应用程式并不能实现删除任务或伫列。
第2种方法是,採用鍊表分配记忆体,可实现动态的创建、删除任务或伫列。系统根据空闲记忆体块的大小按从小到大的顺序组织空闲记忆体鍊表。当应用程式申请一块记忆体时,系统根据申请记忆体的大小按顺序搜寻空闲记忆体鍊表,找到满足申请记忆体要求的最小空闲记忆体块。为了提高记忆体的使用效率,在空闲记忆体块比申请记忆体大的情况下,系统会把此空闲记忆体块一分为二。一块用于满足申请记忆体的要求,一块作为新的空闲记忆体块插入到鍊表中。
下面以图2为例介绍方法2的实现。假定用于动态分配的RAM共有8KB,系统首先初始化空闲记忆体块鍊表,把8KB RAM全部作为一个空闲记忆体块。当应用程式分别申请1KB和2KB记忆体后,空闲记忆体块的大小变为5KB3。2KB的记忆体使用完毕后,系统需要把2KB插入到现有的空闲记忆体块鍊表。由于2 KB<5KB,所以把这2 KB插入5KB的记忆体块之前。若应用程式又需要申请3 KB的记忆体,而在空闲记忆体块鍊表中能满足申请记忆体要求的最小空闲记忆体块为5KB,因此把5KB记忆体拆分为2部分,3KB部分用于满足申请记忆体的需要,2KB部分作为新的空闲记忆体块插入鍊表。随后1KB的记忆体使用完毕需要释放,系统会按顺序把1KB记忆体插入到空闲记忆体鍊表中。
方法2的优点是,能根据任务需要高效率地使用记忆体,尤其是当不同的任务需要不同大小的记忆体的时候。方法二的缺点是,不能把应用程式释放的记忆体和原有的空闲记忆体混合为一体,因此,若应用程式频繁申请与释放“随机”大小的记忆体,就可能造成大量的记忆体碎片。这就要求应用程式申请与释放记忆体的大小为“有限个”固定的值(如图2中申请与释放记忆体的大小固定为l KB、2 KB或3 KB)。方法2的另一个缺点是,程式执行时间具有一定的不确定性。
μC/OS—II提供的记忆体管理机制是把连续的大块记忆体按分区来管理,每个分区中包含整数个大小相同的记忆体块。由于每个分区的大小相同,即使频繁地申请和释放记忆体也不会产生记忆体碎片问题,但其缺点是记忆体的利用率相对不高。当申请和释放的记忆体大小均为一个固定值时(如均为2 KB),FreeRTOS的方法2记忆体分配策略就可以实现类似μC/OS—Ⅱ的记忆体管理效果。
2.5FreeRTOS的移植 FreeRTOS作业系统可以被方便地移植到不同处理器上工作,现已提供了ARM、MSP430、AVR、PIC、C8051F等多款处理器的移植。FreeRTOS在不同处理器上的移植类似于μC/0S一II,故本文不再详述FreeRTOS的移植。此外,TCP/IP协定栈μIP已被移植到FreeRTOS上,具体代码可见FreeRTOS网站。
2.6FreeRTOS的不足 相对于常见的μC/OS—II作业系统,FreeRTOS作业系统既有优点也存在不足。其不足之处,一方面体现在系统的服务功能上,如FreeRTOS只提供了讯息伫列和信号量的实现,无法以后进先出的顺序向讯息伫列传送讯息;另一方面,FreeRTOS只是一个作业系统核心,需外扩第三方的GUI(图形用户界面)、TCP/IP协定栈、FS(档案系统)等才能实现一个较複杂的系统,不像μC/OS-II可以和μC/GUI、μC/FS、μC/TCP-IP等无缝结合。
系统功能
作为一个轻量级的作业系统,FreeRTOS提供的功能包括:任务管理、时间管理、信号量、讯息伫列、记忆体管理、记录功能等,可基本满足较小系统的需要。FreeRTOS核心支持优先权调度算法,每个任务可根据重要程度的不同被赋予一定的优先权,CPU总是让处于就绪态的、优先权最高的任务先运行。FreeRTOS核心同时支持轮换调度算法,系统允许不同的任务使用相同的优先权,在没有更高优先权任务就绪的情况下,同一优先权的任务共享CPU的使用时间。
FreeRTOS的核心可根据用户需要设定为可剥夺型核心或不可剥夺型核心。当FreeRTOS被设定为可剥夺型核心时,处于就绪态的高优先权任务能剥夺低优先权任务的CPU使用权,这样可保证系统满足实时性的要求;当FreeRTOS被设定为不可剥夺型核心时,处于就绪态的高优先权任务只有等当前运行任务主动释放CPU的使用权后才能获得运行,这样可提高CPU的运行效率。
结 论
在嵌入式领域,FreeRTOS是不多的同时具有实时性,开源性,可靠性,易用性,多平台支持等特点的嵌入式作业系统。目前,FreeRTOS已经发展到支持包含X86,Xilinx,Altera等多达30种的硬体平台,其广阔的套用前景已经越来越受到业内人士的瞩目。
版本发布
FreeRTOS V8.2.1 2015年3月.24日
新增对MSP432的支持。