嵌入开发一般需要两套设备
Host:
宿主机,用来完成源代码编辑,编译,显示一部分运行结果等
操作系统可以是 unix, linux, windows等,
硬件可以是PC,工作站等
Target:
目标机,就是你要编的程序的运行环境,CPU可能是任何CPU,常用的有ARM, MIPS, PowerPC, DragonBall 等,或者一些单片机,操作系统常用的有Linux,EPOC, Nucleus, Vxworks, PocetPC, Palm等,或者根本没有操作系统.
Host采用哪种系统,要看Target的CPU所需的编译器可以在哪种系统上跑以及你愿意花多少钱买相应的编译器,常见的有GCC, SDS, DIAB-SDS, Intel的SDT等。
Host和Target之间的通信方式有:
串口:这个最简单,缺点是速度慢,小型嵌入系统常用
并口:这个用的比较少(或许是我见得少吧,只见过一种开发板支持这种方式,显然速度比串口快)。
网卡:这个最快,最稳定,缺点是如果Target的CPU不支持内建的网卡的话,需要在target板上单独加上网卡芯片,对于产品不需要网卡的系统导致最终产品和开发板区别较大,带来一定的开发风险.
USB:这个现在比较常用,速度也还不错,没有网卡稳定,但现在很多产品都支持此USB client,比如数码相机,高端PDA,高档手机等.
有些Target为了调试上的方便同时支持多种通信方式.
Target的存储系统从软件的观点来看我把它分为两类:
1.执久存储器,特点断电之后数据仍然在,实际中可能是ROM, FLASH或小硬盘什么的,当然用FLASH的最多,这些存储器可以被CPU直接寻址(ROM或一部分FLASH)或通过某一个控制器存取(硬盘,另一类FLASH(CF卡,SD卡等)), 我把这一类统称为ROM. 所有的Target里至少有一部分可以被CPU直接寻址的ROM,不然没法启动了.
2.普通的RAM,通常有SDRAM, SRAM等,用DRAM的很少了,特点是断电之后数据就没了,统称为RAM
(少数系统没有RAM,只有一些CPU内部的寄存器,比如一些单片机)
嵌入开发的过程通常是在host上写完代码,编译后通过上面的通信接口传到target里。代码在target里运行有下面两种情况:
1.编译完后的机器码download到target的ram里,然后执行.
2.编译完后的机器码烧入(burn)到target的rom里某一个地址处,代码直接在rom里运行或被一个类似于PC里的bios的程序load到ram里运行.
CPU在上电后都从某一固定的地址(一般这个地址是0)处取出指令运行,所以Target里地址0处一般是ROM,里面会存有一小段程序,类似于PC上的bios程序,这段程序的功能根据硬件系统的不同功能也不一定,但一般有这几个功能:
1.配制CPU运行所需的一些硬件信息,比如片选设置,存储器地址分配等
2.跟Host通信
3.擦除或写FLASH
为方便叙述,我们把这一小段程序叫BootLoader
有了BootLoader,在Host端就可以写个程序或者是用某个工具跟BootLoader交互,把编译好的程序或一段数据传输入到Target里去了,或是发个命令让BootLoader干点事(比如从某个地址开始执行一段程序,或把ram里的某一段程序写到某个地址开始的flash中)
BootLoader从哪里来? 开发板的提供商(一般是CPU的制造商)会提供CPU的参考电路, 一个基本的BootLoader及参考源代码等资料,根据自已开发板的具体硬件配置,在基本的BootLoader的基础上改改就有了.
怎么把BootLoader弄到Target的地址0开始的Rom里去? 我所知道的有下面一些方法(这个根具体的CPU相关)
1.把ROM芯片从Target上拔下来,用写入器把BootLoader写入后再插回去
2.某些Target板上设有外接接口,接上外接的某种东东后,Target可以从外接的这个东东上的ROM里启动,比如Intel的开发板用的JTAG就属这种,在这种板子上接上JTAG后,HOST就可以通过JTAG跟Target通信.
3.某些CPU有一种特殊的工作模式,可以通过硬件条线切换,在这种工作模式下CPU可以跟HOST直接通信并完成最简单的某些功能,比如写某个地址的ram,读某个地址的ram,跳到某个地址去运行等.
有了BootLoader后理论上讲你就可以想干什么就干什么了.
下面说一下如何调试程序,两种方法:
1.打LOG
2.设断点,单步运行等
打LOG很容易,Target能跟Host程序通信后,把要打印的信息传给Host,HOST端可以启动个通讯程序显示一下接收到的东东就好.比如把嵌入linux下把printf重定向输出到uart1,在Host端启动超级终端(Host用windows的话) 或MiniCom(Host用Linux的话), 其实Target上如果有多个通信接口的话Host可以有多个,比如我就同时用两台机器当Host,Window系统启动超级终端显示LOG, Linux Host提供NFS server服务和当Telent客户端使用,我们的Target同时支持串口和USB接口,Target里的Linux启动时通过USB接口上跑的RPC协议把Linux Host硬盘上的某个目录Mount成Target的Root file system,并在Target上启动一个Telnet Server,这样从Linux Host上就可以telnet到Target上,并且方便的实现Target和Host的文件互访。
有些Target有LCD显示器或LED指示灯,用这些也可以做最基本的调试信息输出
设断点单步运行这种调试方式实现起来就比较麻烦了,我就我的理解说说看,事实上我觉得所有的调试工具原理都是这样的,包括的SDS, Total/db, GDB等
调试器的功能主要包括:
1.在某个地址处设断点
大多数CPU都支持一些专用调试指令,比如x86系统的软中断调用Int 3, 设断点只需把指定内存地址处原来的指令保存起来换成调试指令就行了,CPU执行到这一指令时会自已停下来,把系统执行权交给调试器.
2.从某个地址处开始执行程序
这个很easy,调试器[恢复所需的寄存器后]一个jmp指令就行了
3.显示内存某一地址的内容
4.显示寄存器的内容
5.在支持分页式内存管理的CPU和操作系统中实现内存地址空间的映射.
这三个功能不用说了根据具体的CPU和操作系统很容易实现
6.实现source code到二进制代码的对应
这个跟编译器相关,比如GCC, 加上调试选项编译的结果会有符号表等一些调试信息, GDB使用这些调试信息来完成对应.
上面说的这6项事实上PC上的程序调试器也都大概是这样的,嵌入系统所用的调试器与PC上的调试器区别在于调试器被分成两部分,一部分在Target上运行,另一部分在Host端运行,这两部分通过某种方式(串口,USB,网线等)通信,比如GDB, 调试的过程是先在Target端启动一个GDBserver,GDBserver负责完成上面的功能1, 2, 3, 4, 和5,6的一部分.Host端运行GDB,跟GDBServer建立连接之后负责显示和给程序员提供UI.也有一些Target的板的BootLoader就可以完成类似于GDBServer的功能.还有些调试器在启动时会先跟BootLoader通信,装入一个类似于GDBServer功能的程序,运行之, 再装入真正要调试的程序运行之.比如Intel的SDT
上面这些是一般的嵌入系统开发环境的工作原理, 我觉得理解这些后再学习一种新的开发环境有半天时间熟悉一下就基本可以开始工作了.
水平有限,有些东东可能表达的不太准确
试图在互联网上划出国界的举动是愚蠢的!!!
把人当成猪羊圈养,草料永远都不够!把人当人待,人有无限的创造力! “人口减少一半,人们两倍富有”的观念为“一种非常糟糕的自甘堕落—这背后的潜台词是,似乎中国人是封闭围栏中的动物,对周围那些自己赖以生存的资源,除了咀嚼,别无办法。”
我的像册:
http://picasaweb.google.com/bjwf2000/
我的主页:
http://bjwf2000.googlepages.com/