FreeRTOS(读作"free-arr-toss")是一个嵌入式系统使用的开源实时 *** 作系统。FreeRTOS被设计为“小巧,简单,和易用”,能支持许多不同硬件架构以及交叉编译器。
FreeRTOS自2002年Richard Barry开始开发以来,一直都在积极开发中。至于我,我不是FreeRTOS的开发人员或贡献者,我只不过是一个最终用户和爱好者。因此,这章将着重与FreeRTOS架构之“是什么”和“怎么做”,而相对本书其他章节来说,较少去讲“为什么”。
就像所有 *** 作系统一样,FreeRTOS的主要工作是执行任务。大部分FreeRTOS的代码都涉及优先权、调度以及执行用户自定义任务。但又与所有其他 *** 作系统不同,FreeRTOS是一款运行在嵌入式系统上的实时 *** 作系统。
到本章结束,我希望你可以了解FreeRTOS的基本架构。大部分FreeRTOS致力于执行任务,所以你可以很好地看到它究竟是如何做到的。
如果这是你首次去深入了解一个 *** 作系统,我还是希望你可以学习到最基本的 *** 作系统是如何工作的。FreeRTOS是相对简单的,特别是相比Windows,linux,或者OS X而言,不过所有 *** 作系统都有着相同的概念和目标,所以不论学习哪个 *** 作系统都是有启发和有趣的。
3.1 什么是“嵌入式”和“实时”?“嵌入式”和“实时”对于不同的人来说代表不同的理解,所以让我们像FreeRTOS用户那样来定义它们。
嵌入式系统就是一个专门设计用来做一些简单事情的计算机系统,就像是电视遥控器,车载GPS,电子手表,或者起搏器这类。嵌入式系统比通用计算机系统显著的区别在于更小和更慢,通常也更便宜。一个典型的低端嵌入式系统可能有一个运行速度为25MHz的8位CPU,几KB的内存,和也许32KB的闪存。一个高端的嵌入式系统可能有一个运行速度为750MHz的32位CPU,一个GB左右的内存,和几个GB的闪存。
实时系统是设计去完成一定时间内的事,它们保证这些事是在应该做的时候去做。
心脏起搏器是实时嵌入式系统的一个极好例子。起搏器必须在正确的时间收缩心肌,以挽救你的生命;它不能够太忙而没有及时响应。心脏起搏器以及其他的实时嵌入式系统都必须精心设计,以便在任何时刻都能及时执行它们的任务。
3.2架构概述FreeRTOS是一个相对较小的应用程序。最小化的FreeRTOS内核仅包括3个(.c)文件和少数头文件,总共不到9000行代码,还包括了注释和空行。一个典型的编译后(二进制)代码映像小于10KB。
FreeRTOS的代码可以分解为三个主要区块:任务,通讯,和硬件接口。
●任务:大约有一半的FreeRTOS的核心代码用来处理多数 *** 作系统首要关注的问题:任务。任务是给定优先级的用户定义的C函数。task.c和task.h完成了所有有关创建,调度,和维护任务的繁重工作。
●通讯:任务很重要,不过任务间可以互相通讯则更为重要!它给我们带来FreeRTOS的第二项任务:通讯。大约40%的FreeRTOS核心代码是用来处理通讯的。queue.c和queue.h是负责处理FreeRTOS的通讯的。任务和中断使用队列互相发送数据,并且使用信号灯和互斥来发送临界资源的使用情况。
●硬件接口:接近9000行的代码拼凑起基本的FreeRTOS,是硬件无关的;相同的代码都能够运行,不论FreeRTOS是运行在不起眼的8051,还是最新、最炫的ARM内核上。大约有6%的FreeRTOS的核心代码,在硬件无关的FreeRTOS内核与硬件相关的代码间扮演着垫片的角色。我们将在下个部分讨论硬件相关的代码。
硬件注意事项
硬件无关的FreeRTOS层在硬件相关层之上。硬件相关层声明了你选择什么样的芯片架构。图3.1显示了FreeRTOS的各层。
图3.1:FreeRTOS的软件层
FreeRTOS包含所有你需要用来启动很运行系统的硬件无关以及硬件相关的代码。它支持许多编译器(CodeWarrior,GCC,IAR等)也支持许多处理器架构(ARM7,ARM Cortex-M3,PICs各系列,Silicon Labs 8051, x86等)。请参阅FreeRTOS网站,可以看到处理器和编译器支持列表。
FreeRTOS是高可配置设计。FreeRTOS可以被编译成为适合单CPU,极简RTOS,只之支持少数任务的 *** 作系统,也可以被编译成为适合多核功能强大的结合了TCP/IP,文件系统,和USB的怪兽。
配置选项可以通过设置不同的#defines,在FreeRTOSConfig.h文件里选择。时钟速度,堆大小,互斥,和API子集,连同其他许多选项,都可以在这个文件中配置。这里是几个例子,设置了任务优先级的最大数量,CPU的频率,系统节拍器的频率,最小的堆栈大小和总的堆大小:
#define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 5 )
#define configCPU_CLOCK_HZ ( 12000000UL )
#define configTICK_RATE_HZ ( ( portTIckType ) 1000 )
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 100 )
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 4 * 1024 ) )
对于不同的交叉编译器和CPU架构,硬件相关代码分布在多个文件中。举例来说,如果你使用ARM Cortex-M3芯片,IAR编译器工作,那么硬件相关的代码就存在FreeRTOS/Source/portable/IAR/ARM_CM3/目录下。portmacro.h文件声明了所有硬件特定功能,port.c和portasm.s 包含了所有实际硬件相关的代码。硬件无关的头文件portable.h在编译的时候用#include's引入正确的portmacro.h文件。FreeRTOS使用#define'd调用在portmacro.h中声明的硬件特定功能。
让我们来看一个例子,FreeRTOS是如何调用一个硬件相关功能的。硬件无关的文件tasks.c常常需要插入一个代码的临界区,以防止抢占。在不同架构上,插入一个临界区的表现也不同,并且硬件无关的task.c不需要了解硬件相关的细节。所以task.c调用全局宏指令portENTER_CRITICAL(), 乐得忽略它实际上是如何做到的。假设我们使用IAR编译器在ARM Crotex-M3芯片上编译生成FreeRTOS,使用那个定义了portENTER_CRITICAL()的文件/Source/portable/IAR/ARM_CM3/portmacro.h,如下所示:
#define portENTER_CRITICAL() vPortEnterCritical()
vPortEnterCritical()实际上是在FreeRTOS/Source/portable/IAR/ARM_CM3/port.c中定义的。这个port.c文件是一个硬件相关的文件,同时包含了对IAR编译器和Cortex-M3芯片认识的代码文件。vPortEnterCritical()函数利用这些硬件特定的知识进入临界区,又返回到与硬件无关的task.c中。
protmacro.h文件也定义了一个数据类型的基本架构。这个数据类型中包括了基本整型变量,指针,以及系统时钟节拍器的数据类型,在ARM Cortex-M3 chips上使用IAR编译器时,就采用如下定义:
#define portBASE_TYPE long // Basic integer variable type
#define portSTACK_TYPE unsigned long // Pointers to memory locations
typedef unsigned portLONG portTickType; // The system timer tick type
这样使用数据类型的方法,和函数透过小层的#defines,看上去略微有点复杂,不过它允许了FreeRTOS能够被重新编译在一个完全不同的系统架构上,仅仅只需要通过修改这些硬件相关的文件。同时,如果你想要让FreeRTOS运行在一个当前尚未被支持的架构上,你只仅仅需要去实现硬件相关的功能,这要比在FreeRTOS上去实现硬件无关的部分,要少得多。
就如同我们已经见到的,FreeRTOS用C的预处理宏#define来实现硬件相关的功能。FreeRTOS也同样用#define来应对大量的硬件无关的代码。对于非嵌入式应用程序这样频繁使用#define是一个严重的错误,不过在许多小型嵌入式系统中这点开销比起“实时”所提供的功能来说就微不足道了。
3.3. 调度任务:快速概述任务优先级和就绪列表
所有任务都有一个用户指定优先级,从0(最低优先级)到 configMAX_PRIORITIES-1的编译时间值(最高优先级)。例如,如果configMAX_PRIORITIES设置为5,当FreeRTOS使用5个优先等级时:0(最低优先级),1,2,3,和4(最高优先级)。
FreeRTOS使用一个“就绪列表”来跟踪所有已经准备好运行的任务。它像一个任务列表数组来实现就绪列表,如下所示:
static xList pxReadyTasksLists[ configMAX_PRIORITIES ]; /* Prioritised ready tasks. */
pxReadyTasksLists[0]是所有准备好的优先级为0的任务列表,pxReadyTasksLists[1]是所有准备好的优先级为1的任务列表,以此类推,直到pxReadyTasksLists[configMAX_PRIORITIES-1]。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)