http://blog.sina.com.cn/s/blog_b6720a6c01019xyp.html
freeRTOS和UCOS-II是目前在小型实时系统里用得比较多的两个操作系统。这两个操作系统既有相同之处,也有各自的特点。本文将对这两个系统进行具体的比较。虽然本文的观点是基于对这两个系统多年的实际应用,但是并不能够保证在所用的情况下都是适用的。“具体问题具体分析”,对于计算机科学也是如此。
据Richard Barry自述,多年前(~2003)他在做软件咨询工作时感到市场上缺乏一种可靠、好用、开源、有文档、有支持的操作系统,于是自己动手写了freeRTOS。现在freeRTOS是由freertos.org开发和维护。本文论及的是freeRTOSV7.1.0,发表于2011年12月13日。
freeRTOS开源并且免费,可以用于任何商业或非商业场合。
UCOS-II的前身是UCOS,1992年由Jean J. Labrosse发表,1998年UCOS升级为UCOS-II,2009年更新为UCOS-III。本文论及的版本为UCOS-II 2.5.1,发表于2001年。UCOS、UCOS-II、UCOS-III
开源但不免费,需要购买许可证才能用于商业目的。
在UCOS-II里,每一个任务(task)都有自己独有的优先权和独有的一个TCB结构。结构里面包含优先权(OSTCBPrio)、堆栈指针(OSTCBStkPtr)、事件指针(OSTCBEventPtr)等等信息。系统里所有的任务连成一个双向链。UCOS-II里最基本的任务间通讯机制是事件(event),其他的通讯机制,如信号(semaphore)、互斥(mutex)、旗标(flag)、信箱(mailbox)、队列(queue),都是基于事件而实现的。每一个事件都有自己的OS_Event结构,里面有事件种类(OSEventType)、等待事件的任务(OSEventTbl)等等信息。USCOS-II里用来进入和退出关键区域(critical section)的函数是OSEnterCritical和OSExitCritical。
在freeRTOS里每一个任务也有自己的tskTCB结构,里面包含优先权(uxPriority)、堆栈指针(pxTopOfStack)等。同一个优先权上可以有多个任务。任务被放置在pxReadyTasksLists、xDelayedTaskList或xPendingReadyList任务链里。系统里最基本的通讯机制是队列(queue),其他的如信号(semaphore)、互斥(mutex)都是基于队列而实现的。每一个队列有自己的xQUEUE结构,里面有读写指针(pcWriteTo、pcReadFrom)以及等待读写的任务(xTasksWaitingToSend、xTasksWaitingToReceive)等信息。freeRTOS用来进入和退出关键区域的函数是portENTER_CRITICAL和portExit_CRITICAL。
对于关键区域,UCOS-II提供了一个局域(local)变量OS_CPU_SR用来保存和恢复某些处理器状态(cpu status),如中断屏蔽设置等;freeRTOS没有提供类似的机制,而是通过ulCriticalNesting变量来决定是否屏蔽中断。
UCOS-II里的每一个任务只能处于以下的某个状态:沉寂(dormant)、等待(waiting)、就绪(ready)、执行(running)、中断(ISR running)。每一个任务在数组OSRdyTbl里有一个对应位,任务就绪对应位就置‘1’。系统根据OSRdyTbl里的信息选择任务进行抢占式(peremptive)调度。
freeRTOS把任务分成4种状态:就绪(ready)、执行(running)、挂起(suspended)、阻塞(blocked)。任务在某个时刻只会处在某一个任务链中。系统根据任务链的内容进行协调式(cooperative)或者抢占加轮流(preemptive + round robin)式调度。
在两个系统里,抢占式调度都是通过时钟节拍中断(time tick interrupt)来实现的。任务的主动切换也可以通过触发软件中断来实现,但不是非得如此才行,各个移植(porting)可以有自己的选择。
中断管理的方式主要不是由操作系统决定的,而是与处理器本身所提供的中断数据保存和恢复机制更紧密相联。对于同样的处理器,
UCOS-II和freeRTOS的中断管理方式几乎可以完全一样,主要要做的事情都是:首先保存处理器和寄存器(registers)的状态,然后具体处理中断事件,最后恢复处理器和寄存器的状态,或者切换到另一个任务。需要指出的是,因为实时系统的特殊要求,冗长的中断处理或者嵌套(nested)的中断都是不可取的。
UCOS-II把内存区域(memory partition)分成相同大小的内存块来使用,从而避免了内存碎化(fragmentation)带来的困扰。这种内存管理方式的缺点在于:大小不同的内存块必须提前订制,无法通用。
freeRTOS里最常用到的内存管理方式是:不固定内存块的大小;选择满足要求的最小空闲内存块使用,并将多余的部分划分出去形成一个新的内存块。这种管理方式有可能产生碎片,不过使用起来要方便一些。
freeRTOS和
UCOS-II都配置有信号(semaphore)、互斥(mutex)等各种功能。这些功能并不是每一个项目都用得到。不需要的功能可以从操作系统里剪裁出去。在UCOS-II里,可以通过编辑头文件OS_CFG.H来剪裁;在freeRTOS里应该编辑的文件是FreeRTOSConfig.h。
适当的剪裁可以减小系统并提高系统的速度。但是对于大多数的项目来说,处理器的大部分时间应当不是花在操作系统上(如果不是这样的话,是不是应该使用操作系统就成了一个需要考虑的问题了),所以对操作系统的剪裁不必追求尽善尽美。出于同样的原因,一定要说某个操作系统比另一个小,或者比另一个快,都没有太大的实际意义。
本文作者曾经把
UCOS-II和freeRTOS移植到数个处理器上,并长时间运行网页服侍、图像显示、红外遥控等程序。在数天、有时数个星期的运行中,两个操作系统都表现得极为稳定。
据本文作者的经验,如果系统不稳定,问题基本不会出在操作系统本身,而是很可能在于操作系统的移植有漏洞,或者中断的处理不成功。移植和中断的查错都很不容易,需要有很好的耐心和经验。
操作系统的移植从来就不是一件简单的事,要求对处理器、操作系统、汇编语言和软件编译工具有非常细致的了解。
freeRTOS的移植通常需要修改3个文件:
- portmacro.h:主要是用来保存和恢复处理器和寄存器状态的宏(macro)定义。
- port.c: 主要是对任务堆栈的初始化。
- portISR.c: 主要是对各个中断(包括时钟节拍中断)的处理和对关键区域的处理。
UCOS-II的移植也是需要修改3个文件:
- OS_CPU.H:主要是对关键区域的处理。
- OS_CPU_A.ASM:主要是用来保存和恢复处理器和寄存器状态。
- OS_CPU_C.C:主要是对任务堆栈的初始化。
很明显,两个系统的移植工作量大致相等。
UCOS-II发布的时间较早,有很多的伴随软件包(uC/TCP-IP,uC/GUI,uC/USB等等),有众多的用户,有众多的移植,并且提供各种正规培训。freeRTOS发布的时间要迟得多,伴随软件包比较少,不过因为是开源而且免费,已经有很多的移植,所以影响力增长很快。
freeRTOS和UCOS-II是功能和适用场合都非常相似的两个实时操作系统。两者的主要区别在于商业模式和支持程度的不同。