当前,arm公司的32位risc处理器,以其内核耗电少、成本低、功能强、特有16/32位双指令集,已成为移动通信、手持计算、多媒体数字消费等嵌入式解决方案的risc标准,市场占有率超过了75 %。多家公司都推出了自己的基于arm内核的处理器产品,越来越多的开发人员开始了针对arm平台的开发。通常开发人员需要购买芯片厂商或第三方提供的开发板,还需要购买开发软件,如c编译器或者集成了实时操作系统的开发环境。开发板的价格从数百到上千美元,而编译器、实时操作系统价格更是动辄数千到数万美元。这样,在开发初期,软硬件上的投资就需要上万美元,对于国内大多数开发人员来说,无疑是太贵了。
庆幸的是,gnu所倡导的自由软件给开发者带来了福音。1984 年,旨在开发一个类似 unix 的,并且是完全免费的完整操作系统和配套工具:gnu 系统(发音为“guh-new”)。gnu的操作系统和开发工具都是免费的,遵循gnu 通用公共许可证 (gpl)协议,任何人都可以从网上获取全部的源代码。关于gnu和公共许可证协议的详细资料,读者可参看gnu网站的中文介绍:http://www.gnu.org/home.cn.html。
除了大家熟知的linux操作系统外,gnu的软件还包括编译器(gcc,g++)、二进制转换工具(objdump,objcopy)、调试工具(gdb,gdbserver,kgdb)和基于不同硬件平台的开发库。gnu开发工具的主要缺点是采用命令行方式,用户掌握和使用比较困难,不如基于 windows系统的开发工具好用。但是,gnu工具的复杂性是由于它更贴近编译器和操作系统的底层,并提供了更大的灵活性。一旦学习和掌握了相关工具,也就了解了系统设计的基础知识,为今后的开发工作打下基础。gnu的开发工具都是免费的,遵循gpl协议,任何人都可以从网上获取。笔者参与了一个基于 arm平台的嵌入式linux系统开发,采用的是摩托罗拉龙珠系列的mc928mx1。从测试代码、引导程序、嵌入式linux移植、应用程序、图形界面都可以用gnu工具进行开发,不需要在开发工具上做额外的投入。本文所介绍的开发方法同样适用于其它公司的基于arm的产品。
1 硬件平台
mc928mx1(以下简称mx1)是摩托罗拉公司基于arm核心的第一款mcu,主要面向高端嵌入式应用。内部采用arm920t内核,并集成了sdram/flash、lcd、usb、蓝牙(bluetooth)、多媒体闪存卡(mmc)、cmos摄像头等控制器。关于mx1的详细资料,感兴趣的读者可以参考http://www.motorola.com.cn /semiconductors/。作为应用开发的最小系统必须包括ram(程序运行空间)、flash(存放目标代码)和串行接口(用于调试和下载程序)。mx1提供了6个片选端(cs0“cs5),内置了sdram控制器,数据宽度32位。在笔者的系统中采用了2片8m%26;#215;16位的 sdram和2片4m%26;#215;16位的同步flash存储器,分别接入数据线的低16位和高16位,如图1所示。
图1中sdram接片选端cs2,flash接片选端cs3,其余为sdram/flash的控制信号。最小系统还包括至少1个串行接口,可以采用 mx1内置的uart控制器。
2 自举模式
目前,许多嵌入式处理器都提供了自举模式(bootstrap),供用户写入引导代码。自举模式利用了固化在芯片内部的一段引导程序,当处理器复位时,如果在特定引脚上加信号,则处理器将在复位后执行固化rom中的程序。例如,mx1提供了4条复位引脚,复位时引脚不同的电平组合可以从不同的片选端启动系统。自举rom中的程序完成串口的初始化,然后等待用户从串口写入用户代码。自举模式所能接受的是一种专门格式的文本文件,包括数据和要写入/读出的地址。关于自举模式的代码格式,可参考相关芯片的手册。在摩托罗拉的网站还提供了许多小工具,帮助开发者将其它格式的文件转换成为自举模式格式。通过自举模式下载的通常是一段和上位机软件(如超级终端)通信的程序,完成接收数据并写入flash的操作。写入的数据可以是用户自己的应用程序、数据或者操作系统的内核。通过自举模式下载的引导程序同样可以用gnu工具开发。
3 gnu的编译器和开发工具
gnu提供的编译工具包括汇编器as、c编译器gcc、c++编译器g++、连接器ld和二进制转换工具objcopy。基于arm平台的工具分别为 arm-linux-as、arm-linux-gcc、arm-linux-g++、arm -linux-ld 和arm-linux-objcopy。gnu的所有开发工具都可以从www.gnu.org上下载,基于arm的工具可以从 www.uclinux.org获得。gnu的编译器功能非常强大,共有上百个操作选项,这也是这类工具让初学者头痛的原因。不过,实际开发中只需要用到有限的几个,大部分可以采用缺省选项。gnu工具的开发流程如下:编写c、c++语言或汇编源程序,用gcc或g++生成目标文件,编写连接脚本文件,用连接器生成最终目标文件(elf格式),用二进制转换工具生成可下载的二进制代码。gnu工具都运行在linux下,开发者需要1台运行linux的pc 作为上位机。由于篇幅所限,不能完整地介绍整个嵌入式操作系统的开发过程,将以第二节中提到的通过自举模式下载的引导程序为例,说明开发的过程。对于像 linux这样的大系统,基本的开发流程是一样的。
引导程序将通过自举模式下载到mx1的片内ram,从地址0x00300000开始并执行。完成串口和sdram的初始化后,引导程序将等待接收应用程序或操作系统内核,将接收到的数据放在sdram中。数据接收完毕后,引导程序将sdram中的数据写入flash,下一次就可以从flash中直接引导系统了。由于操作系统的内核比较大,如linux有1 mb以上,下载过程必须考虑纠错。因此,接收部分采用xmode协议,可以用windows下超级终端的xmode发送方式发送文件。
(1)编写c、c++语言或汇编源程序
通常汇编源程序用于系统最基本的初始化,如初始化堆栈指针、设置页表、操作arm的协处理器等。初始化完成后就可以跳转到c代码执行。需要注意的是,gnu的汇编器遵循at%26;amp;t的汇编语法,读者可以从gnu的站点(www.gnu.org)上下载有关规范。汇编程序的缺省入口是 start标号,用户也可以在连接脚本文件中用entry标志指明其它入口点(见下文关于连接脚本的说明)。
(2)用gcc或g++生成目标文件
如果应用程序包括多个文件,就需要进行分别编译,最后用连接器连接起来。如笔者的引导程序包括3个文件:init.s(汇编代码、初始化硬件) xmrecever.c(通信模块,采用xmode协议)和flash.c(flash擦写模块)。 分别用如下命令生成目标文件: arm-linux-gcc-c-o2-o init.o init.s arm-linux-gcc-c-o2-o xmrecever.o xmrecever.c arm-linux-gcc-c-o2-o flash.o flash.c 其中-c命令表示只生成目标代码,不进行连接;-o 命令指明目标文件的名称;-o2表示采用二级优化,采用优化后可使生成的代码更短,运行速度更快。如果项目包含很多文件,则需要编写makefile文件。关于makefile的内容,请感兴趣的读者参考相关资料。
(3)编写连接脚本文件
gcc等编译器内置有缺省的连接脚本。如果采用缺省脚本,则生成的目标代码需要操作系统才能加载运行。为了能在嵌入式系统上直接运行,需要编写自己的连接脚本文件。编写连接脚本,首先要对目标文件的格式有一定了解。gnu编译器生成的目标文件缺省为elf格式。elf文件由若干段(section)组成,如不特殊指明,由c源程序生成的目标代码中包含如下段:.text(正文段)包含程序的指令代码;.data(数据段)包含固定的数据,如常量、字符串;.bss(未初始化数据段)包含未初始化的变量、数组等。c++源程序生成的目标代码中还包括.fini(析构函数代码)和.init(构造函数代码)等。有关elf文件格式,读者可自行参考相关资料。连接器的任务就是将多个目标文件的.text、.data和.bss等段连接在一起,而连接脚本文件是告诉连接器从什么地址开始放置这些段。例如笔者的引导程序连接文件link.lds为: entry(begin) section { 。=0x00300000; .text : { *(.text) } .data: { *(.data) } .bss: { *(.bss) } }
其中,entry(begin)指明程序的入口点为begin标号;。=0x00300000指明目标代码的起始地址为0x00300000,这一段地址为mx1的片内ram;.text : { *(.text) }表示从0x00300000开始放置所有目标文件的代码段,随后的.data: { *(.data) }表示数据段从代码段的末尾开始,再后是.bss段。
(4)用连接器生成最终目标文件
有了连接脚本文件,如下命令可生成最终的目标文件: arm-linux-ld-nostadlib-o bootstrap.elf-t link.lds init.o xmrecever.o flash.o 其中,ostadlib表示不连接系统的运行库,而是直接从begin入口;-o指明目标文件的名称;-t指明采用的连接脚本文件;最后是需要连接的目标文件列表。
(5)生成二进制代码
连接生成的elf文件还不能直接下载执行,通过objcopy工具可生成最终的二进制文件: arm-linux-objcopy-o binary bootstrap.elf bootstrap.bin 其中-obinary指定生成为二进制格式文件。objcopy还可以生成s格式的文件,只需将参数换成-o srec。如果想将生成的目标代码反汇编,还可以用objdump工具: arm-linux-objdump-d bootstrap.elf 至此,所生成的目标文件就可以直接写入flash中运行了。如果要通过自举模式下载,还需要转换为自举模式的文件格式,相关转换工具可以在摩托罗拉的网站上找到。
掌握了gnu工具后,开发者就可以开发或移植c或c++代码的程序。用户可以不需要操作系统,直接开发简单应用程序。但对于更复杂的应用来说,操作系统必不可少。目前流行的源代码公开的操作系统如linux、μc/os都可以用gnu工具编译。arm的linux已有很多成熟的版本,可以支持 arm720、arm920、 arm1020等多种处理器,读者可从www.uclinux.org或www.armdevzone.com上获取最新信息。linux移植过程中和处理器相关的代码都放在arch/arm目录下。对于内核,用户需要做的是设定自己系统的内存映像,ram起始地址,i/o地址空间和虚拟i/o地址空间,参看arch/arm/mach-integrator/arch.c文件。除了内核外,用户还需要为自己的系统编制各种各样的驱动程序。
4 调试工具
linux下的gnu调试工具主要是gdb、gdbserver和kgdb。其中gdb和gdbserver可完成对目标板上linux下应用程序的远程调试。gdbserver是一个很小的应用程序,运行于目标板上,可监控被调试进程的运行,并通过串口与上位机上的gdb通信。开发者可以通过上位机的gdb输入命令,控制目标板上进程的运行,查看内存和寄存器的内容。gdb5.1.1以后的版本加入了对arm处理器的支持,在初始化时加入-target==arm参数可直接生成基于arm平台的gdbserver。gdb工具可以从ftp://ftp.gnu.org/pub/gnu /gdb/上下载。
对于linux内核的调试,可以采用kgdb工具,同样需要通过串口与上位机上的gdb通信,对目标板的linux内核进行调试。由于篇幅所限,感兴趣的读者可以从http://oss.sgi.com/projects/kgdb/上了解具体的使用方法。
结束语
本文以一个具体的实例为例,对gnu工具中的常用功能作了介绍。其实gnu工具的功能还远不止这些,更进一步的操作有:针对不同处理器,不同算法的软件优化、高效的内嵌汇编、大型项目管理功能等。相信gnu能成为越来越多开发人员的选择。
单机片运用在那些方面呢?影响单片机晶振报价的五大要素是什么?
olarWinds hack 暴露了云技术的缺陷
电动汽车基本普及但为什么还没有电动飞机呢?
TI推出业界最高精度差动放大器INA149
转载 | 高性能计算与AI网络大融合,如何重塑网络智能时代?
用GNU工具开发基于ARM的嵌入式系统
开发工程师注意!2014年值得关注的9项技术
新唐蓝牙低功耗MCU带你快速实现摄影灯光应用
智能汽车、自动驾驶热度居高不下——答对这两个问题,你就真的懂自动驾驶了!
英伟达推出图形处理器GTX 1080 速度比旗舰芯片快一倍
河南正式启动了博鳌乐城低碳智慧能源与智能电网综合示范区项目
德州仪器Q2净利润14.05亿美元,模拟产品贡献90%利润
上海正式打响百兆以下家庭宽带“消灭战”
德州仪器与中国电力科学研究院联合签署智能电网战略合作备忘录
工业制造业的智能化机遇:从业务需求出发,寻找AI的机会点
51单片机编程开发(一)之C语言基础一
多模介质波导滤波器的设计过程简介
我国传统制造业已正式开始向智能制造转型的方向迈进
什么时候才能让无人驾驶在中国上路?
无源软开关Boost电路图