多数Linux系统是在PC平台上运行,然而Linux做为嵌入式系统也是很是稳定的。本文描绘了一个嵌入式系统的概览,并展现嵌入式系统产品是如何使用Linux的。 嵌入式系统比摩西还老的故事node
电 脑用于控制设备或嵌入系统的历史几乎电脑自身的历史同样长。在通信领域,六十年代晚期,电脑被用于电子电话交换机,称为“存储程序控制”系统。“电脑”这 词那时并不广泛,存储程序指内存装有程序和例程信息。存储控制逻辑,而不是将其固化在硬件中,在当时确实是突破性的。今天,咱们认为它原本就应如此。程序员
那时的电脑是为每个应用而定制的,按今天的标准,它们是一些不正常的、由奇怪的特殊指令和I/O设备集成在一部电脑中。编程
微处理器经过提供构建大系统模块的小型、低成本、CPU引擎改变了这一切。它提出了外设经过总线联接的固定硬件架构及称为编程的通常编程模型。浏览器
软件也随着硬件提出。最初,编写和测试软件只有简单的编程开发工具。每一个项目实际运行的软件一般来自于草稿的修改。编程经常使用汇编语言或宏语言,由于编译器经常有缺陷和缺少完善的调试工具。软件构建模块和标准化库只是到了七十年代才流行起来的概念。服务器
嵌 入式系统的商品化操做系统在1970年代后期才出现,许可能是用汇编语言写成的,而且只能用于特定的微处理器,当微处理器被淘汰时,它的操做系统除非为新处 理器重写,不然也要被淘汰。今天,许多这类早期的系统成了些模糊的记忆;还有谁记得MTOS吗?当C语言出现时,操做系统编写的效率、稳定性、可移植性都 提升了不少。这一点在管理上马上表现出来,它为微处理器被淘汰时保护软件投资带来了但愿。对于市场来讲这是一个好消息。用C语言写成的操做系统今天愈来愈 广泛。通常来讲,可重复使用的软件已经占主导并越作越好。网络
在 八十年代早期,我最喜欢的操做系统是Wendon操做系统,大约150美圆就能够获得一个C源码库。它是一个包,你能够经过选择部件创建本身的操做系统, 相似在菜单上点菜。例如,你能够在库清单上点工做排程安排和内存管理方案。 不少嵌入式系统的商品化操做系统是在八十年代出现的。这一热潮持续到如今,今天,有不少可行的商品化操做系统可供选择。一些大佬出现了,如 VxWorks, pSOS, Neculeus和Windows CE。架构
许多嵌入式系统根本没有操做系统,只有循环控制。对于一些简单设备这是足够的,可是随着系统愈来愈复杂,操做系统就很必要了或软件变得难以想象的复杂。不幸的是,有些复杂得可怕的嵌入式系统只由于设计者坚持不要操做系统才那么复杂。框架
渐渐地,更多嵌入式系统须要与各种网络联接,所以须要网络功能。即使是酒店的门把手也嵌入了微处理器与网络相联。 对于仅仅是编码控制循环的嵌入式系统,增长网络功能将致使系统复杂程度提升以至要求操做系统。模块化
除 了商品化操做系统,还有大量专用操做系统。其中大部分来自于草案,如CISCO的IOS;还有是从其余操做系统中派生出来的。例如,许多操做系统是从同一 版本的Berkeley Unix系统派生,由于它有完整的网络功能。其余是基于主要操做系统的如KA9Q来自Phil Karn。工具
Linux做为嵌入式系统是一个带有不少优点的新成员。它对许多CPU和硬件平台都是可移植的、稳定、功能强大、易于开发。
工具包突破ICE的障碍
开发嵌入式系统的关键的是可用的工具包。像任何工做同样,好的工具使得工做更快更好。开发的不一样阶段须要不一样的工具。
传 统上,首先用于开发嵌入式系统工具是内部电路仿真器(ICE),它是一个相对昂贵的部件,用于植入微处理器与总线之间的电路中,容许使用者监视和控制微处 理器全部信号的进出。这有点难作,由于它是异体,可能会引发不稳定。可是它提供了总线工做的清晰情况,免了许多对硬件软件底层工做情况的猜想。
过 去,一些工做依赖ICE为主要调试工具,用于整个开发过程。可是,一旦初始化软件对串口支持良好的话,多数的调试能够不用ICE而用其余方法进行。较新的 嵌入式系统利用很是清晰的微处理器设计。有时,相应工做初始码已经有了可以快速得到串口工做。这意味着没有ICE人们也可以方便地工做。省去ICE下降了 开发的成本。一旦串口开始工做,它能够支持各类专业开发工具。
Linux是基于GNU的C编译器,做为GNU工具链的一部分,与gdb源调试器一块儿工做。它提供了开发嵌入式Linux系统的全部软件工具。这有些典型的、用于在新硬件上开发嵌入式Linux系统的调试工具。
1. 写入或植入引导码
2. 向串口打印字符串的编码,如“Hello World”(事实上我更喜欢“Watson,Come hre I need you”,电话上经常使用的第一个词。)
3. 将gdb目标码植入工做串口,这可与另外一台运行gdb程序的Linux主机系统对话。只要简单地告诉gdb经过串口调试程序。它经过串口与测试机的gdb 目标码对话,你能够进行C源代码调试,也能够用这个功能将更多的码载入RAM或Flash Memory中。
4. 利用gdb让硬件和软件初始化码在Linux内核启动时工做。
5. 一旦Linux内核启动,串口成为Linux控制口并可用于后续开发。利用kgdb,内核调试版的gdb,这步经常不做要求,若是你与网络联接,如10BaseT,下一步你可能要启动它。
6. 若是在你的目标硬件上运行了完整的Linux内核,你能够调试你的应用进程。利用其余的gdb或覆盖gdb的图形如xgdb。
什么是实时系统?
嵌 入式系统经常被错误地分为实时系统, 尽管多数系统通常并不要求实时功能。实时是一个相对的词,纯化论者经常严格地定义实时为对一事件以预约的方式在极短的时间如微秒做出响应渐渐地,在如此短 暂时间间隔内的严格实时功能在专用DSP芯片或ASIC上实现了。只有在设计低层硬件FIFO、分散/汇集DMA引擎和定制硬件时才会有这样的要求。
许多设计人员由于对真实的要求设有清晰的理解而对实时的要求焦虑不安。对于大多数的系统,在一至五微秒的近似实时响应已经足够。一样软需求也是能够接受的。如 Windows 98 已经崩溃的中断必须在4毫秒内(±98%)内、或20毫秒(±0)内进行处理。
这种软要求是比较容易知足的,包括环境转换时间、中断等待时间、任务优先级和排序。环境转换时间曾是操做系统的一个热门话题。总之,多数 CPU 这些要求处理得很好,并且CPU的速度如今已经快了不少,这个问题也就不重要了。
严格的实时要求一般由中断例程或其余内核环境驱动程序功能处理,以确保稳定的表现,等待时间,一旦请求出现要求服务的时间很大程度上取决于中断的优先及其余能暂时掩盖中断的软件。
中 断必须进行处理和管理以确保时间要求能符合,如同许多其余的操做系统。在IntelX86处理器中,这工做很容易由Linux实时扩展处理。这是提供了一 个之后台任务方式运行Linux的中断处理调度。关键的中断响应没必要通知Linux。所以能够获得许多对于关键时钟的控制。在实时控制级和时间限制宽松的 基本Linux级之间提供接口,这提供了与其余嵌入式操做系统类似的实时框架。所以,实时关键代码是隔开的、并“设计”成知足要求的。代码处理的结果是以 更通常的方法也许只在应用任务级。
嵌入式系统定义
一 个观点是若是一个应用没有用户界面,它必须是嵌入式的,由于用户不能直接与之交互。固然这是简单化的。一个电梯控制的电脑被认为是嵌入式的:按键选择楼层 指示灯显示电梯的停层。对于联网的嵌入式系统,若是系统包含监视和控制的网络浏览器,这种界限就更加模糊了。更好些的定义注重系统的集中的功能和主要的目 的。
由于Linux提供了完成嵌入功能的基本的内核和你所须要的全部用户界面,它是多面的。它能处理嵌入式任务和用户界面。将Linux看做是连续的统一体,从一个具备内存管理、任务切换和时间服务及其余的分拆的、微内核到完整的服务器,支持全部的文件系统和网络服务。
一个小型的嵌入式Linux系统只须要下面三个基本元素:
引导工具
Linux微内核,由内存管理、进程管理和事务处理构成
初始化进程:
若是要让它能干点什么且继续保持小型化,还得加上:
硬件驱动程序
提供所需功能的一个或更多应用程序。
再增长功能,或许须要这些
一个文件系统(也许在ROM或RAM中)
TCP/IP网络堆栈
存储半过渡数据和交换用的磁盘。
硬件平台
选 择最好的硬件是一个复杂的工做、充满了公司其余项目的政治、偏见、传统,缺少完整或精确的信息。 成本常常是关键的议题。当考虑成本时、确信你在考虑产品的整个成本、不只是CPU。有时快的、便宜的CPU一旦加上总线逻辑和时延使之与外设一块儿工做,能 变成一个昂贵的狗的产品。若是你在寻找软件,首先是硬件已经有产品了。若是你是系统设计者,由你决定制定实时的预算及硬件的工做是否满意。
现实中须要多快的CPU来完成一项工做,而后放大三倍。奇怪,CPU理论上的速度竟与现实中同样,别忘了应用程序将会充分利用cache。
想 象总线的速度须要多快,若是有其余总线如PCI总线,包括进来。慢的总线或产生DMA阻塞的总线会下降CPU的速度形成拥挤。 有集成设备的CPU是好的,由于只须调试不多的设备,而且支持通用CPU的驱动程序一般都很容易得到。在个人项目中,芯片与外设的联接常常出问题或不知足 咱们所需的兼容性。由于外设是集成的,不要认为这会便宜。
将10斤重的Linux塞入只能装5斤的袋中
对于Linux一个共同的认识是它用于嵌入式系统简直是神奇极了。这可能不大对,典型的PC上的Linux 对PC用户来讲功能有多。
对初学者而言,能够将内核与任务分开,标准的Linux内核一般驻留在内存中,每个应用程序都是从磁盘运到内存上执行。当程序结束后,它所占用的内存就被释放,程序就被下载了。
在一个嵌入式系统里,可能没有磁盘。有两种途径能够消除对磁盘的依赖,这要看系统的复杂性和硬件的设计。
在一个简单的系统里,当系统启动后,内核和全部的应用程序都在内存里。这就是大多数传统的嵌入式系统工做模式,它一样能够被Linux支持。
有 了Linux,就有了第二种可能性。由于Linux已经有能力“加载”和“卸载”程序,一个嵌入式系统就能够利用它来节省内存。试想一个典型的包括一个大 概8MB到16MB的Flash Memory和8MB内存的系统。Flash Memory能够做为一个文件系统。Flash Memory驱动程序用来链接Flash Memory和文件系统。做为替代,可以使用Flash Disk。这Flash部件用软件仿真磁盘。其中一个例是M-Systems的DiskOnChip,能够达到160MB。(http://www.m- systems.com)。全部的程序都以文件形式存储在Flash文件中,须要时能够装入内存。这种动态的、“根据须要加载”的能力是支持其它一系列功 能的重要特征:
它 使初始化代码在系统引导后被释放。Linux一样有不少内核外运行的公用程序。这些一般程序在初始化时运行一次,之后就再也不运行。并且,这些公用程序能够 用它们相互共有的方式,一个接一个按顺序运行。这样,相同内存空间能够被反复使用以“召入”每个程序,就象系统引导同样。这的确能够节省内存,特别是那 些配置一次之后就再也不更改的网络堆栈 若是Linux可加载模块的功能包括在内核里,驱动程序和应用程序就均可以被加载。它能够检查硬件环境而且为硬件装上相应的软件。这就消除了用一个程序占 用许多Flash Memory来处理多种硬件的复杂性。
软件的升级更模块化。你能够在系统运行的时候在Flash上升级应用程序和可加载驱动程序。
配置信息和运行时间参数能够做为数据文件储存在Flash上。
非虚拟内存
标准 Linux 的另外一个待征是虚拟内存的能力。正是这种神奇的特征使应用程序员能够狂热的编写代码而不计后果,无论程序有多大。程序溢出到了磁盘交换区。在没有磁盘的嵌入式系统里,一般不能这么作。
在嵌入式系统里不须要这种强大的功能。实际上,你可能不但愿它在实时的关键系统里,由于它会带来没法控制的时间因素。这个软件必须设计得更加精悍,以适合市面上物理内存,就象其它嵌入式系统同样。
注意因为CPU的缘由,一般在Linux中保存虚拟内存代码是明智的,由于将它清除很费事。并且还有另一个缘由是它支持共享文本,这样就可使许多程序共享一个软件。没有这个,每个程序都要有它本身的库,就象printf同样。
虚拟内存的调入功能能够被关掉,只要将交换空间的大小设置为零。而后,若是你写的程序比实际的内存大,系统就会看成你的运行用尽了交换空间来处理;这个程序将不会运行,或者malloc将会失灵。
在 许多CPU上,虚拟内存提供的内存管理能够将不一样程序分开,防止它们写到其它地址的空间上。这在嵌入式系统上一般不可能,由于它只支持一个简单、扁平的地 址空间。Linux的这种功能有助于其发展。它减小了胡乱的编写程序形成系统崩溃的可能性。许多嵌入式系统基于效率方面的缘由有意识使用程序间能够共享的 “全局”数据。这也能够经过Linux共享内存功能来支持,共享的只是指定的内存部分。
文件系统
许多嵌入式系统没有磁盘或者文件系统。Linux不须要它们也能运行。如前所述,应用程序任务能够和内核一块儿编写,而且在引导时做为一个影像加载。对于简单的系统来讲,这就够了。然而,它缺少前面所说的灵活性。
实 际上,许多商业性嵌入式系统,提供文件系统做为选项。许多或者是专用的文件系统或者是MS-DOS-Compatible文件系统。Linux提供MS- DOS-Compatible文件系统,同时还有其它多种选择。之因此提供其它选择是由于它们更增强大并且具备容错功能。Linux还具备检查和维护的功 能,商业性供应商每每不提供这些。这对于Flash系统来讲尤为重要,由于它是经过网络更新的。若是系统在升级过程当中失去了能力,那它就没有用了。维护的 功能一般能够解决这类问题。
文件系统能够被放在传统的磁 盘驱动器、Flash Memory或其它这类的介质上。并且,用于暂时保存文件,一个小RAM盘就足够了。Flash Memories被分割成块。这些块中也许包括一个含有当CPU启动时运行的最初的软件的引导块。这可能包括Linux 引导代码。剩余的Flash能够用做文件系统。Linux的内核能够经过引导代码从Flash复制到RAM,或者还有一个选择,内核能够被存储在 Flash的一个独立部分,而且直接从那里执行。
另外对于一些系统来讲还有一个有趣的选择,那就是将一个便宜的CD-ROM包含在内。这比Flash Memory 便宜,并且经过交换CD-ROM支持简单的升级。有了这个,Linux 只要从 CD-ROM上引导,而且象从硬盘上同样从CD-ROM上得到全部的程序。
最 后,对于联网的嵌入式系统来讲,Linux 支持NFS(Network File System)。这为实现联网系统的许多增值功能打开了大门。第一,它容许经过网络上加载应用程序。这是控制软件修改的基础,由于每个嵌入式系统的软件 均可以在一个普通的服务器上加载。它在运行的时候也能够用来输入或输出大量的数据、配置和状态信息。这对用户监督和控制来讲是一个很是强大的功能。举例来 说,嵌入式系统能够创建一个小的RAM磁盘,包含的文件中有与当前状态信息同步的内容。其它系统能够简单的把这个RAM磁盘设置为基于网络的远程磁盘,并 且空中存取状态文件。这就容许另外一个机器上的Web服务器经过简单的CGI Script存取状态信息。在其它电脑上运行的其它应用程序包能够很容易的存取数据。对更复杂的监控,应用程序包如Matlab(http: //www.mathworks.com/products/matlab/),能够用来在操做员的PC或工做站的提供系统运行的图形展现。
引导LILO和BIOS在哪里
当 一个微处理器第一次启动的时候,它开始在预先设置的地址上执行指令。一般在那里有一些只读内存,包括初始化或引导代码。在PC上,这是BIOS。它执行了 一些低水平的CPU初始化和其它硬件的配置。BIOS 继续辨认哪一个磁盘里有操做系统,把操做系统复制到RAM而且转向它。实际上,这很是复杂,但对咱们的目标来讲也很是重要。在PC上运行的Linux依靠 PC的BIOS来提供这些配置和OS加载功能。
在一个嵌 入式系统里常常没有这种BIOS。这样你就要提供同等的启动代码。幸运的是,嵌入式系统并不须要PC BIOS 引导程序那样的灵活性,由于它一般只须要处理一个硬件的配置。这个代码更简单也更枯燥。它只是一指令清单,将固定的数字塞到硬件寄存器中去。然而,这是关 键的代码,由于这些数值要与你的硬件相符并且要按照特定的顺序进行。因此在大多数状况下,一个最小的通电自检模块,能够检查内存的正常运行、让LED闪 烁,而且驱动其它必须的硬件以使主Linux OS启动和运行。这些启动代码彻底根据硬件决定,不可随意移动。
幸 运的是,许多系统都有为核心微处理器和内存所定制的菜单式硬件设计。典型的是,芯片制造商有一个样本主板,能够用来做为设计的参考或多或少与新设计相同。 一般这些菜单式设计的启动代码是能够得到的,它能够根据你的须要轻易的修改。在少数状况下,启动代码须要从新编写。 为了测试这些代码,你可使用一个包含‘模拟内存’的电路内置模拟器,它能够代替目标内存。你把代码装到模拟器上并经过模拟器调试。若是这样不行,你能够 跳过这一步,但这样就要一个更长的调试周期。
这个代码最终要在较为稳定的内存上运行,一般是Flash或EPROM芯片。你须要使用一些方法将代码放在芯片上。怎么作,要根据“目标”硬件和工具来定。
一 种流行的方法是把Flash或EPROM芯片插入EPROM或Flash烧制器。这将把你的程序“烧”(存)入芯片。而后,把芯片插入你的目标板的插座, 打开电源。这个方法须要板上配有插座,但有些设备是不能配插座的。 另外一个方法是经过一个JTAG界面。一些芯片有JTAG界面能够用来对芯片进行编程。这是最方便的方法。芯片能够永远被焊在主板上,一个小电缆从板上的 JTAG链接器,一般是一个PC卡,联到JTAG界面。下面是PC运行JTAG界面所需的一些惯用程序。这个设备还能够用来小量生产。
健壮性比政治家的承诺更可靠
在PC 硬件上运行时,Linux是很是可靠和稳定的,特别是和如今流行的一些操做系统相比。嵌入式内核自己有多稳定呢?对大多数微处理器来讲,Linux很是 好。移植到新微处理器家族的Linux内核运行起来与本微处理器同样稳定。它常常被移植到一个或多个特定的主板上。这些板包括特定的外围设备和CPU。
幸运的是,许多代码是与处理器的,因此移植集中在差别上。其中大多数是在内存管理和中断控制领域。一旦成功移植,它们就很是稳定。前面咱们讨论过,引导策略普遍依赖于硬件要求,并且你必须有计划地作一些定制的工做。
设 备驱动程序更加混乱:有些稳定有些不稳定。并且选择颇有限;一旦你离开了通用的PC平台,你须要本身编写。幸运的是,周围有许多驱动程序,你可能能够找到 一个与你的需求相近的修改一下。这种驱动程序界面已定义好。许多类的驱动程序都很是相近,因此把磁盘、网络或一系列的端口驱动程序从一个设备移植到另外一个 设备上一般并不难。我发现许多驱动程序都写得很好,很容易理解,但你仍是要准备一本关于内核结构的书在手头。 依个人经验,Linux至少和我用过的著名的商业性操做系统同样稳定。总之,这些操做系统和Linux的问题在于对工做过程微秒之处的误解,而不在于代码 的难度或基本的设计错误。任何操做系统都有不少争论不休的故事,这里不须要重复。Linux的优点在于源代码是公开、注释清晰和文档齐全的。这样,你就可 以控制和处理所出现的任何问题。
伴随着基本内核和驱动程 序,还有其它问题。若是系统有一个硬盘, 那么文件系统的可靠性就成问题。咱们有用磁盘进行Linux系统设计超过两年的经验。这些系统几乎从未正常关闭过。电源随时均可能被中断。感受很是好,使 用的是标准(EXT2)文件系统。标准Linux初始化脚本运行fsck程序,它在检查和清除不稳定的inodes方面很是有效。将默认的每隔30秒运行 更新程序改成每隔5或10秒运行是比较明智的。这样缩短了数据在进入磁盘以前,待在高速缓冲存储器内的时间,下降了丢失数据的可能性。
如何发展
嵌入式Linux的确有它的缺陷。好比,虽然它并不比某些商业竞争对手差多少,但它的确是个贪婪的存储器。这能够经过减小一些没必要要的功能来弥补,但这可能会花很长的时间,并且若是不仔细的话,还可能带来很大的困扰。
许多Linux的应用程序都要用到虚拟内存,在许多嵌入式系统中,是没有价值的,因此不要觉得一个没有磁盘的嵌入式系统能够运行任何Linux应用程序。
内核调试工具都不怎么好,特别是在较底层的。kgdb可使错误定位很是容易,你只要从新启动。不幸的是,打印语句更麻烦。
然 而,对我来讲最糟糕的是心理上的问题。Linux很是的灵活。嵌入式系统总的来讲却不灵活;并且它们彻底是为最有效实现预约功能而严格设计的。如今的趋势 是保持灵活性、保持整体目标功能、尽可能少作修改。这个目标是崇高的,可是,所付出的代价将是针对具体的工做作出巨大的调整。保持灵活性将致使额外的工做, 带着额外的软件包,并且有时还要下降性能。一个反复出现的例子就是配置。考虑在一个网络界面配置IP地址,这一般是经过从启动 script上运行ifconfig程序来完成的。这是一个28K的程序,从配置文件上调用数据,能够用几行代码代替,初始化合适的结构。然而,即便这非 常合理,但它仍然有害,由于它用一种从未使用过的方法扭曲了软件。
Linux在嵌入式系统中的应用是可行的。它有用、可靠。它的发展成本和替代者一致。