基于ARM体系的嵌入式系统BSP的程序设计

时间:2022-05-04 03:13:01 其他范文 收藏本文 下载本文

基于ARM体系的嵌入式系统BSP的程序设计((锦集10篇))由网友“今天该吃什么呢”投稿提供,下面是小编整理过的基于ARM体系的嵌入式系统BSP的程序设计,欢迎您阅读分享借鉴,希望对您有所帮助。

基于ARM体系的嵌入式系统BSP的程序设计

篇1:基于ARM体系的嵌入式系统BSP的程序设计

基于ARM体系的嵌入式系统BSP的程序设计

摘要:在介绍基于ARM体系的嵌入式系统启动流程的基础上,结合编程实例,详细、系统地叙述了BSP(板级支持包)程序的各个组成部分及其具体设计方案,并就实际程序设计中的几个难点问题做了说明。

关键词:ARMBSP嵌入式系统微处理器

ARM公司在32位RISC的CPU开发领域不断取得突破,其结构已经从V3发展到V6。

BSP(BoardSupportPackage)板级支持包介于主板硬件和操作系统之间,其功能与PC机上的BIOS相类似,主要完成硬件初始化并切换到相应的操作系统。BSP是相对于操作系统而言的,不同的操作系统对应于不同定义形式的BSP,例如VxWorks的BSP和Linux的BSP相对于某一CPU来说,尽管实现的功能一样,可是写法和接口定义是完全不同的。另外,仔细研究所用的芯片资料也十分重要,例如尽管ARM在内核上兼容,但每家芯片都有自己的特色。所以这就要求BSP程序员对硬件、软件和操作系统都要有一定的了解。

本文介绍基于ARM体系的嵌入式应用系统初始化部分BSP的程序设计。本文引用的源码全部是基于HMS320C7202芯片设计,并已成功运行。

1初始化过程

尽管各种嵌入式应用系统的结构及功能差别很大,但其系统初始化部分完成的操作有很大一部分是相似的。嵌入式系统的启动流程如图1所示。

1.1设置入口指针

启动程序首先必须定义指针,而且整个应用程序只有一个入口指针。一般地,程序在编译链接时将异常中断向量表链接在0地址处,并且作为整个程序入口点。入口点代码如下:

ENTRY(_start);开始

1.2设置异常中断向量表

ARM要求中断向量表必须放置在从0开始、连续8×4字节的空间内。各异常中断向量地址以及中断的算是优先级如表1:

表1各异常中断的中断向量地址以及中断的处理优先级

中断向量地址异常中断类型异常中断模式优先级(6最低)0x0复位特权模式(SVC)10x4未定义中断未定义指令中止模式(Undef)60x8软件中断(SWI)特权模式(SVC)60x0c指令预取中止中止模式50x10数据访问中止中止模式20x14保留未使用未使用0x18外部中断请求(IRQ)外部中断(IRQ)模式40x1c快速中断请求(FIQ)快速中断(FIQ)模式3

每当一个中断发生后,ARM处理器便强制把程序计数器(PC)指针置为向量表中对应中断类型的地址值。因为每个中断向量仅占据放置1条ARM指令的空间,所以通常放置1条跳转指令或向程序计数器(PC)寄存器赋值的数据访问指令,使程序跳转到相应的异常中断处理程序执行。如果异常中断处理程序起始地址小于32MB,使用B跳转指令;如果跳转范围大于32MB,使用LDR指令。

另外,对于各未用中断,可使其指向一个只含返回指令的哑函数,以防止错误中断引起系统的混乱。

1.3初始化存储系统

初始化存储系统的编程对象是系统的存储器控制器,一个系统可能存在多种存储器类型的接口,不同的存储系统的设计不尽相同。Flash和SRAM同属于静态存储器类型,可以合用一个存储器端口;而DRAM因为有动态刷新和地址线复用等特性,通常配有专用的存储器端口。其中,SDRAM必须在初始化阶段进行设置,因为大部分的程序代码和数据都要在SDRAM中运行。

在HMS30C7202中,与SDRAM配置有关的寄存器有4个:配置寄存器、刷新定时寄存器、写缓冲写回寄存器和等待驱动寄存器,需要根据实际的系统设计对此分别加以正确配置。

SDRAM的初始化过程如下:加电→延迟10ms(各具体SDRAM器件延时时间可能不同)→设置配置寄存器参数→延时→写刷新定时寄存器,设置刷新周期→延时→使能自动刷新→延时→设置模式寄存器(位于SDRAM内部)。

1.4存储器地址分布重映射(remap)和MMU

系统一上电,程序将自动从0地址处开始执行。因此,必须保证在0地址处存在正确的代码,即要求0地址开始入是非易失性的ROM或Flash等。但是因为ROM或Flash的访问速度相对较慢,每次中断响应发生后,都要从读取ROM或Flash上面的向量表开始,影响了中断响应速度。一般程序执行后将SDRAM映射为地址0,并把系统程序加载到SDRAM中运行,其具体步骤可以采用以下的方案:

(1)上电后,从0地址的ROM开始往下执行;

(2)根据映射前的地址,对SDRAM进行必要的代码和数据拷贝;

(3)拷贝完成后,进行重映射操作;

(4)因为RAM在重映射前准备好了内容,使得PC指针能继续在RAM里取得正确的指令。

在这种地址映射的变化过程中,程序员需要仔细考虑的是:程序的执行流程不能被这种变化所打断,注意保证程序流程在重映射前后的承接关系。

存储器的地址分配是很灵活的,可以将I/O操作映射成内存操作,也可以通过映射对某些不可访问的地址空间进行保护等。进行存储器初始化设计时,一定要根据应用程序的具体要求来完成地址分配。对地址管理通过MMU即存储器管理单元实现。

在ARM系统中,MMU通过页式虚拟存储管理,将虚拟空间和物理空间分别分成一个个固定大小的页,并建立两者之间的映射关系,从而实现虚拟地址到物理地址的转换。MMU还可完成存储器访问权限的控制和虚拟存储器空间缓冲特性的设置。

以下是实现MMU的部分代码:

for=(i=1;i<0x1000;i++){

pagetable[i]=(i<<20)|MMU_SECDESC;

}//建立页表,每页大小为1MB,页表偏移序号是物理地址的高12位;

for(addr=SDRAM_BASE;addr<(SDRAM_BASE+SDRAM_SIZE/2);addr+=SIZE_1M)

pagetable[addr>>20]=addr|MMU_SECDESE|

MMU_CACHEABLE|MMU_BUFFERABLE;

//将SDRAM_BASE至(SDRAM_BASE+SDRAM_SIZE/2)空间的设置为不可CACHE和不可BUFFER的

for(addr=SDRAM_BASE+SDRAM_SIZE/2;addr<(SDRAM_BASE+SDRAM_SIZE);addr+=SIZE_1M)

pagetable[addr>>20]=(addr+0x1000000)|

MMU_SECDESC|MMU_CACHEABLE|MMU_BUFFERABLE;

//将这段空间的地址映射关系设置为VA(虚拟地址)=PA(物理地址)+0x1000000

pagetable[0]=(0x42f00000)|MMU_SECDESC|MMU_CACHEABLE|MMU_BUFFERABLE;

//将SDRAM的虚拟地址0x42f00000映射到0处

1.5初始化各模式下的堆栈指针

因为ARM处理器有7种执行状态,每一种状态的堆栈指针寄存器(SP)都是独立的(System和User三项式使用相同SP寄存器)。因此,对程序中需要用到的每一种模式都要给SP寄存器定义一个堆栈地址。方法是改变状态寄存器(CPSR)内的状态位,使处理器切换到不同的状态,然后给SP赋值。这里列出的代码定义了三种模式的SP指针,其中,I_Bit表示IRQ的中断禁止位;F_Bit表示FIQ的`中断禁止位:

@;SetupSVCstacktobe4Kontopofzero-initdata

LDRr1,=installStack

ADDsp,r1,#2048

@;SetupIRQandFIQstacks

MOVr0,#(Mode_IRQ32|I_Bit)

MSRcpsr,r0

MOVr0,r0

ADDsp,r1,#2048*2

MOVr0,#(Mode_FIQ32|I_Bit|F_Bit)

MSRcpsr,r0

MOVr0,r0

ADDsp,r1,#2048*3

一般堆栈的大小要根据需要而定,但是要尽可能给堆栈分配快速和高带宽的存储器。堆栈性能的提高对系统性能的影响是非常明显的。

1.6初始化有特殊要求的端口、设备

有些关键的I/O部件必须在使能IRQ和FIQ之前进行初始化。因为如果在使能IRQ和FIQ之前没有进行初始化,可以产生假的异常中断信号。程序中初始化了HMS30C7202的串口1用来调试程序与其它设备通信。串口1是一个通用全双工异步接收/发送器(UART),它支持16C550的大部分功能。UART有接收缓冲/发送保持寄存器、波特率除数锁存器、中断允许寄存器等9个寄存器。对串口1的初始化主要是对各寄存器的设置,其实现代码如下所示:

_outb(ser_base+0x30,1);

_outw(0x8002301c,0xffff9f9f);GPIOPORTAEnable

Register

_outw(0x800230A4,0x6060);GPIOPORTAMultiFunctionelect-Register

serial_outb(SERIAL_LCR,0x80);

serial_outb(SERIAL_LCR,0x80);

serial_outb(SERIAL_DLL,baud_data[cur_baud]);

serial_outb(SERIAL_DLM,0x0);

serial_outb(SERIAL_LCR,0x03);

seial_outb(SERIAL_FCR,0x01);

serial_outb(SERIAL_IER,0x00);

serial_outb(SERIAL_MCR,0x03);

1.7切换处理器模式,开中断

最后转换到应用程序运行所需的最终模式,一般是User模式。不要过早切换到User模式进行User模式的堆栈设备。因为进入User模式后就不能再操作CPRS回到别的模式了,可能会对接下去的程序执行造成影响。

这时才使能异常中断,通过清除CPRS寄存器中的中断禁止位实现。如果过早地开中断,在系统初始化之前就触发了有效中断,会导致系统的死机。

1.8呼叫主应用程序

当所有的系统初始化工作完成后,就需要把程序流程转入主应用程序。

图2

2技术难点分析

2.1多种语言的混合编程

ARM有两种汇编指令集:16位THUMB指令集和32位ARM指令集。使用16位的寄存器可以降低成本,而且16位THUMB指令集整体执行速度比ARM32位指令集快,提高了代码密度。为了满足ARM子程序和Thumb子程序互相调用,必须保证编写的代码遵循ATPCS。ATPCS规定了子程序调用的基本规则。

ARM系统结构也支持C、C++以及汇编语言的混合编程。汇编语言和C/C++语言的混合编程,在一个追求效率的程序中比较常见。许多人认为像BSP这样底层的程序应该用纯汇编语言编写,其实不然。用汇编语言编写的程序可读性不高,而且不宜维护,不便于向其它类型的CPU移植,而这些方面却是C语言程序的优势。BSP能否用纯C语言去写呢?也不行。因为某些操作是用C实现不了的。例如操作特殊寄存器的指令、CP15寄存器的指令、中断使能及堆栈地址的设定等。在汇编和C/C++之间的函数调用时,也要遵循ATPCS的定义,还要注意的是用C语言编写嵌入式程序时,要避免使用不能被固化到ROM中的库函数。

混合编程情况下的程序编译及链接后的输出代码与没有混合编程时是不同的。所以当多个源文件如果使用了不同的设置进行编译,相互之间的调用可能产生兼容性问题,对此一定要加以仔细考虑。编译时,要告诉编译器和链接器足够的信息,一方面,让编译器能够使用正确的指令码进行编译;另一方面,在不同的状态之间发生函数调用时,链接器将插入一段链接代码(veneers)来实现状态转换。

2.2MMU的实现过程

页表是实现MMU的重要手段。页表存放在内存中,从虚拟地址到物理地址的变换过程其实就是查询页表的过程。大小为1MB的存储块通常被称为段,图2说明了如何查表进行段式寻址的全过程:32位的虚拟地址可分为12位的一级页表序号和20位的段内地址偏移。12位的一级页表序号和CP15寄存器的C2中的18位变换表基址合并成一级描述符地址查表找出相应的一级描述符;然后,段对应的物理基地址与段内地址偏移量合并成为真正的存储器存取地址即物理地址,读出相应数据。

本文介绍的BSP程序已经在以HMS30C7202为主芯片的开发系统上运行并测试通过,并且成功地引导了Linux内核,文中引用代码可以直接使用。今后可以在此基础上添加命令行解释程序,在引导操作系统前进行存存储器的读写等,扩展开发系统的功能。

篇2:基于ARM体系的嵌入式系统BSP的程序设计

基于ARM体系的嵌入式系统BSP的程序设计

摘要:在介绍基于ARM体系的嵌入式系统启动流程的基础上,结合编程实例,详细、系统地叙述了BSP(板级支持包)程序的各个组成部分及其具体设计方案,并就实际程序设计中的几个难点问题做了说明。

关键词:ARM BSP 嵌入式系统 微处理器

ARM公司在32位RISC的CPU开发领域不断取得突破,其结构已经从V3发展到V6。

BSP(Board Support Package)板级支持包介于主板硬件和操作系统之间,其功能与PC机上的BIOS相类似,主要完成硬件初始化并切换到相应的操作系统。BSP是相对于操作系统而言的',不同的操作系统对应于不同定义形式的BSP,例如VxWorks的BSP和Linux的BSP相对于某一CPU来说,尽管实现的功能一样,可是写法和接口定义是完全不同的。另外,仔细研究所用的芯片资料也十分重要,例如尽管ARM在内核上兼容,但每家芯片都有自己的特色。所以这就要求BSP程序员对硬件、软件和操作系统都要有一定的了解。

本文介绍基于ARM体系的嵌入式应用系统初始化部分BSP的程序设计。本文引用的源码全部是基于HMS320C7202芯片设计,并已成功运行。

1 初始化过程

尽管各种嵌入式应用系统的结构及功能差别很大,但其系统初始化部分完成的操作有很大一部分是相似的。嵌入式系统的启动流程如图1所示。

1.1 设置入口指针

启动程序首先必须定义指针,而且整个应用程序只有一个入口指针。一般地,程序在编译链接时将异常中断向量表链接在0地址处,并且作为整个程序入口点。入口点代码如下:

ENTRY(_start) ;开始

1.2 设置异常中断向量表

ARM要求中断向量表必须放置在从0开始、连续8×4字节的空间内。各异常中断向量地址以及中断的算是优先级如表1:

表1 各异常中断的中断向量地址以及中断的处理优先级

中断向量地址异常中断类型异常中断模式优先级(6最低)0x0复位特权模式(SVC)10x4未定义中断未定义指令中止模式(Undef)60x8软件中断(SWI)特权模式(SVC)60x0c指令预取中止中止模式50x10数据访问中止中止模式

[1] [2] [3] [4] [5] [6]

篇3:ARM程序设计优化

程序优化是指软件编程结束后,利用软件开发工具对程序进行调整和改进,让程序充分利用资源, 提高运行效率, 缩减代码尺寸的过程,按照优化的侧重点不同, 程序优化可分为运行速度优化和代码尺寸优化。运行速度优化是指在充分掌握软硬件特性的基础上, 通过应用程序结构调整等手段来降低完成指定任务所需执行的指令数。在同一个处理器上, 经过速度优化的程序比未经优化的程序在完成指定任务时所需的时间更短,即前者比后者具有更高的运行效率。代码尺寸优化是指,采取措施使应用程序在能够正确完成所需功能的前提下, 尽可能减少程序的代码量。

然而在实际的程序设计过程中,程序优化的两个目标(运行速度和代码大小) 通常是互相矛盾的。为了提高程序运行效率,往往要以牺牲存储空间、增加代码量为代价, 例如程序设计中经常使用的以查表代替计算、循环展开等方法就容易导致程序代码量增加。而为了减少程序代码量、压缩存储器空间,可能又要以降低程序运行效率为代价。因此, 在对程序实施优化之前, 应先根据实际需求确定相应的策略。在处理器资源紧张的情况下, 应着重考虑运行速度优化;而在存储器资源使用受限的情况下, 则应优先考虑代码尺寸的优化。

1 程序运行速度优化

程序运行速度优化的方法可分为以下几大类。

1.1 通用的优化方法

(1)减小运算强度

利用左/ 右移位操作代替乘/ 除2 运算:通常需要乘以或除以2 的幂次方都可以通过左移或右移n 位来完成。实际上乘以任何一个整数都可以用移位和加法来代替乘法。ARM 7 中加法和移位可以通过一条指令来完成,且执行时间少于乘法指令。例如: i = i × 5 可以用i = (i《2) + i 来代替。

利用乘法代替乘方运算:ARM7 核中内建有32 ×8 乘法器, 因此可以通过乘法运算来代替乘方运算以节约乘方函数调用的开销。例如: i = pow(i, 3.0) 可用 i = i×i × i 来代替。

利用与运算代替求余运算:有时可以通过用与(AND )指令代替求余操作(% )来提高效率。例如:i = i % 8 可以用 i = i & 0x07 来代替。

(2)优化循环终止条件

在一个循环结构中,循环的终止条件将严重影响着循环的效率,再加上arm 指令的条件执行特性,所以在书写循环的终止条件时应尽量使用count-down-to-zero结构。这样编译器可以用一条BNE (若非零则跳转)指令代替CMP (比较)和BLE (若小于则跳转)两条指令,既减小代码尺寸,又加快了运行速度。

(3)使用inline 函数

arm C 支持 inline 关键字,如果一个函数被设计成一个inline 函数,那么在调用它的地方将会用函数体来替代函数调用语句, 这样将会彻底省去函数调用的开销。使用inline 的最大缺点是函数在被频繁调用时,代码量将增大。

1.2 处理器相关的优化方法

(1)保持流水线畅通

从前面的介绍可知,流水线延迟或阻断会对处理器的性能造成影响,因此应该尽量保持流水线畅通。流水线延迟难以避免, 但可以利用延迟周期进行其它操作。

LOAD/STORE 指令中的自动索引(auto-indexing)功能就是为利用流水线延迟周期而设计的。当流水线处于延迟周期时, 处理器的执行单元被占用, 算术逻辑单元(ALU )和桶形移位器却可能处于空闲状态,此时可以利用它们来完成往基址寄存器上加一个偏移量的操作,

供后面的指令使用。例如:指令 LDR R1, [R2], #4 完成 R1= *R2 及 R2 += 4 两个操作,是后索引(post-indexing)的例子;而指令 LDR R1, [R2, #4]! 完成 R1 = *(R2 + 4) 和 R2 +=4 两个操作,是前索引(pre-indexing)的例子。

流水线阻断的情况可通过循环拆解等方法加以改善。一个循环可以考虑拆解以减小跳转指令在循环指令中所占的比重, 进而提高代码效率。下面以一个内存复制函数加以说明。

void memcopy(char *to, char *from, unsigned int nbytes)

{

while(nbytes--)

*to++ = *from++;

}

为简单起见,这里假设nbytes 为16 的倍数(省略对余数的处理)。上面的函数每处理一个字节就要进行一次判断和跳转, 对其中的循环体可作如下拆解:

void memcopy(char *to, char *from, unsigned int nbytes)

{

while(nbytes) {

*to++ = *from++;

*to++ = *from++;

*to++ = *from++;

*to++ = *from++;

nbytes - = 4;

}

}

这样一来, 循环体中的指令数增加了,循环次数却减少了。跳转指令带来的负面影响得以削弱。利用arm 7 处理器32 位字长的特性, 上述代码可进一步作如下调整:

void memcopy(char *to, char *from, unsigned int nbytes)

{

int *p_to = (int *)to;

int *p_from = (int *)from;

while(nbytes) {

*p_to++ = *p_from++;

*p_to++ = *p_from++;

*p_to++ = *p_from++;

*p_to++ = *p_from++;

nbytes - = 16;

}

}

经过优化后,一次循环可以处理16 个字节。跳转指令带来的影响进一步得到减弱。不过可以看出, 调整后的代码在代码量方面有所增加。

(2)使用寄存器变量

CPU 对寄存器的存取要比对内存的存取快得多, 因此为变量分配一个寄存器, 将有助于代码的优化和运行效率的提高,

整型、指针、浮点等类型的变量都可以分配寄存器; 一个结构的部分或者全部也可以分配寄存器。给循环体中需要频繁访问的变量分配寄存器也能在一定程度上提高程序效率。

1.3 指令集相关的优化方法

有时可以利用arm7 指令集的特点对程序进行优化。

(1)避免除法

arm 7 指令集中没有除法指令,其除法是通过调用C 库函数实现的。一个32 位的除法通常需要20~140 个时钟周期。因此, 除法成了一个程序效率的瓶颈, 应尽量避免使用。有些除法可用乘法代替,例如: if ( (x / y) 》 z)可变通为 if ( x 》 (y × z)) 。在能满足精度,且存储器空间

冗余的情况下, 也可考虑使用查表法代替除法。当除数为2 的幂次方时, 应用移位操作代替除法。

(2)利用条件执行

arm 指令集的一个重要特征就是所有的指令均可包含一个可选的条件码。当程序状态寄存器(PSR )中的条件码标志满足指定条件时, 带条件码的指令才能执行。利用条件执行通常可以省去单独的判断指令,因而可以减小代码尺寸并提高程序效率。

(3)使用合适的变量类型

arm 指令集支持有符号/ 无符号的8 位、16 位、32位整型及浮点型变量。恰当的使用变量的类型,不仅可以节省代码,并且可以提高代码运行效率。应该尽可能地避免使用char、short 型的局部变量,因为操作8 位/16 位局部变量往往比操作3 2 位变量需要更多指令, 请对比下列3 个函数和它们的汇编代码。

intwordinc(inta) wordinc

{ ADD a1,a1,#1

return a + 1; MOV pc,lr

} shortinc

shortshortinc(shorta) ADD a1,a1,#1

{ MOV a1,a1,LSL #16

return a + 1; MOV a1,a1,ASR #16

} MOV pc,lr

charcharinc(chara) charinc

{ ADD a1,a1,#1

return a + 1; AND a1,a1,#&ff

} MOV pc,lr

可以看出, 操作3 2 位变量所需的指令要少于操作8位及16 位变量。

1.4 存储器相关的优化方法

(1)用查表代替计算

在处理器资源紧张而存储器资源相对富裕的情况下, 可以用牺牲存储空间换取运行速度的办法。例如需要频繁计算正弦或余弦函数值时,可预先将函数值计算出来置于内存中供以后查找。

(2)充分利用片内RAM

一些厂商出产的arm 芯片内集成有一定容量的RAM,如Atmel 公司的AT91R40807 内有128KB 的RAM,夏普公司的LH75400/LH75401 内有32KB 的RAM。处理器对片内RAM 的访问速度要快于对外部RAM 的访问,所以应尽可能将程序调入片内RAM 中运行。若因程序太大无法完全放入片内RAM ,可考虑将使用最频繁的数据或程序段调入片内RAM 以提高程序运行效率。

1.5 编译器相关的优化方法

多数编译器都支持对程序速度和程序大小的优化,有些编译器还允许用户选择可供优化的内容及优化的程度。相比前面的各种优化方法, 通过设置编译器选项对程序进行优化不失为一种简单有效的途径。

2 代码尺寸优化

精简指令集计算机的一个重要特点是指令长度固定, 这样做可以简化指令译码的过程,但却容易导致代码尺寸增加。为避免这个问题,可以考虑采取以下措施来缩减程序代码量。

2.1 使用多寄存器操作指令

arm 指令集中的多寄存器操作指令LDM/STM 可以加载/ 存储多个寄存器,这在保存/ 恢复寄存器组的状态及进行大块数据复制时非常有效。例如要将寄存器R4~R12 及R14 的内容保存到堆栈中,若用STR 指令共需要10 条,而一条STMEA R13!, {R4 ?? R12, R14} 指令就能达到相同的目的,节省的指令存储空间相当可观。不过需要注意的是, 虽然一条LDM/STM 指令能代替多条LDR/STR 指令,但这并不意味着程序运行速度得到了提高。实际上处理器在执行LDM/STM 指令的时候还是将它拆分成多条单独的LDR/STR 指令来执行。

2.2 合理安排变量顺序

arm 7 处理器要求程序中的32 位/16 位变量必须按字/ 半字对齐,这意味着如果变量顺序安排不合理, 有可能会造成存储空间的浪费。例如:一个结构体中的4个32 位int 型变量i1 ~ i4 和4 个8 位char 型变量c1 ~ c4,若按照i1、c1、i2、c2、i3、c3、i4、c4 的顺序交错存放时, 由于整型变量的对齐会导致位于2 个整型变量中间的那个8 位char 型变量实际占用32 位的存储器,这样就造成了存储空间的浪费。为避免这种情况, 应将int 型变量和char 型变量按类似i1、i2、i3、i4、c1、c2、c3、c4 的顺序连续存放。

2.3 使用Thumb 指令

为了从根本上有效降低代码尺寸,ARM 公司开发了16 位的Thumb 指令集。Thumb 是ARM 体系结构的扩充。Thumb 指令集是大多数常用32 位ARM 指令压缩成16 位宽指令的集合。在执行时,16 位指令透明的实时解压成32 位ARM 指令并没有性能损失。而且程序在Thumb状态和ARM 状态之间切换是零开销的。与等价的32 位arm 代码相比,Thumb 代码节省的存储器空间可高达35% 以上。

结语

综上所述,优化的过程是在透彻了解软/ 硬件结构和特性的前提下,充分利用硬件资源,不断调整程序结构使之趋于合理的过程。其目的是最大程度发挥处理器效能,最大限度利用资源,尽可能提高程序在特定硬件平台上的性能。随着ARM 处理器在通信及消费电子等行业中的应用日趋广泛,优化技术将在基于arm 处理器的程序设计过程中发挥越来越重要的作用。

值得注意的是,程序的优化通常只是软件设计需要达到的诸多目标之一, 优化应在不影响程序正确性、健壮性、可移植性及可维护性的前提下进行。片面追求程序的优化往往会影响健壮性、可移植性等重要目标。

篇4:如何学习arm嵌入式

学习arm嵌入式方法

基础部分:基础打不牢的工程师必然是走不远的。

汇编语言、C语言,数据结构和算法、操作系统都是必须要懂得的。当然了,如果能用开发板把机械手臂和智能小车这样的项目自己动手开发一下,效果就更好了,一方面是降低了学习的枯燥,另一方面自己动了手也会增加实际经验。

嵌入式应用层开发:

Linux系统编程、网络编程、UcOS、通信协议及编程技术、GUI-Qt、图形化界面开发等等。这部分技术所对应的工程师是目前国内相当缺乏的,也是嵌入式开发者就业最多的地方。虽然工资没有做底层得高,但个把万还是能够轻松实现的。

嵌入式底层开发:

linuxkernel(linux内核)、rootfile(根文件系统),系统移植,linux驱动程序这些技术最好都懂一些。你在这里需要用到一个运行计算能力更强的arm开发板来做辅助,测试你的底层代码是否能够运行,像尚观提供给学员的就是cortex—a9的三星 exnoys 4412四核平台。

学习嵌入式系统之基础知识

1、Linux 基础

安装Linux操作系统:Linux文件系统 ,Linux常用命令,Linux启动过程详解,熟悉Linux服务能够独立安装Linux操作系统,能够熟练使用Linux系统的基本命令,认识Linux系统的常用服务安装Linux操作系统,Linux基本命令实践,设置Linux环境变量,定制Linux的服务,Shell 编程基础使用vi编辑文件,使用Emacs编辑文件,使用其他编辑器。

2、Shell 编程基础

Shell简介:认识后台程序Bash编程熟悉Linux系统下的编辑环境,熟悉Linux下的各种Shell,熟练进行shell编程熟悉vi基本操作,熟悉Emacs的基本操作,比较不同shell的区别,编写一个测试服务器是否连通的shell脚本程序,编写一个查看进程是否存在的shell脚本程序,编写一个带有循环语句的shell脚本程序。

3、Linux下的 C 编程基础

linux C语言环境概述:Gcc使用方法:Gdb调试技术,Autoconf Automake Makefile,代码优化,熟悉Linux系统下的开发环境,熟悉Gcc编译器,熟悉Makefile规则编写Hello,World程序,使用make命令编译程序,编写带有一个循环的程序,调试一个有问题的程序。

4、嵌入式系统开发基础

嵌入式系统概述:交叉编译配置TFTP服务,配置NFS服务,下载Bootloader和内核,嵌入式Linux应用软件开发流程熟悉嵌入式系统概念以及开发流程,建立嵌入式系统开发环境制作cross_gcc工具链,编译并下载U-boot 编译并下载Linux内核编译并下载Linux应用程序。

5、嵌入式系统移植

Linux内核代码:平台相关代码分析,ARM平台介绍,平台移植的关键技术,移植Linux内核到ARM平台,了解移植的概念,能够移植Linux内核移植Linux2.6内核到arm9开发板。

6、嵌入式 Linux 下串口通信

串行I/O的基本概念:嵌入式Linux应用软件开发流程,Linux系统的文件和设备,与文件相关的系统调用,配置超级终端和MiniCOM能够熟悉进行串口通信,熟悉文件I/O,编写串口通信程序,编写多串口通信程序。

7、嵌入式系统中多进程程序设计

Linux系统进程概述:嵌入式系统的进程特点,进程操作,守护进程,相关的系统调用了解Linux系统中进程的概念,能够编写多进程程序编写多进程程序,编写一个守护进程程序,sleep系统调用任务管理、同步与通信Linux任务概述任务调度管道、信号共享内存,任务管理 API,了解Linux系统任务管理机制,熟悉进程间通信的几种方式,熟悉嵌入式Linux中的任务间同步与通信编写一个简单的管道程序实现文件传输,编写一个使用共享内存的程序。

嵌入式系统的分层与专业的分类

1、硬件层,是整个嵌入式系统的根本,如果现在单片机及接口这块很熟悉,并且能用C和汇编语言来编程的话,从嵌入式系统的硬件层走起来相对容易,硬件层也是驱动层的基础,一个优秀的驱动工程师是要能够看懂硬件的电路图和自行完成CPLD的逻辑设计的,同时还要对操作系统内核及其调度性相当的熟悉的。但硬件平台是基础,增值还要靠软件。

硬件层比较适合于,电子、通信、自动化、机电一体、信息工程类专业的人来搞,需要掌握的专业基础知识有,单片机原理及接口技术、微机原理及接口技术、C语言。

2、驱动层,这部分比较难,驱动工程师不仅要能看懂电路图还要能对操作系统内核十分的精通,以便其所写的驱动程序在系统调用时,不会独占操作系统时间片,而导至其它任务不能动行,不懂操作系统内核架构和实时调度性,没有良好的驱动编写风格,按大多数书上所说添加的驱动的方式,很多人都能做到,但可能连个初级的驱动工程师的水平都达不到,这样所写的驱动在应用调用时就如同windows下我们打开一个程序运行后,再打开一个程序时,要不就是中断以前的程序,要不就是等上一会才能运行后来打开的程序。想做个好的驱动人员没有三、四年功底,操作系统内核不研究上几编,不是太容易成功的,但其工资在嵌入式系统四层中可是最高的。

驱动层比较适合于电子、通信、自动化、机电一体、信息工程类专业尤其是计算机偏体系结构类专业的人来搞,除硬件层所具备的基础学科外,还要对数据结构与算法、操作系统原理、编译原理都要十分精通了解。

3、操作系统层,对于操作系统层目前可能只能说是简单的移植,而很少有人来自已写操作系统,或者写出缺胳膊少腿的操作系统来,这部分工作大都由驱动工程师来完成。操作系统是负责系统任务的调试、磁盘和文件的管理,而嵌入式系统的实时性十分重要。据说,XP操作系统是微软投入300人用两年时间才搞定的,总时工时是600人年,中科院软件所自己的女娲Hopen操作系统估计也得花遇几百人年才能搞定。因此这部分工作相对来讲没有太大意义。

4、应用层,相对来讲较为容易的,如果会在windows下如何进行编程接口函数调用,到操作系统下只是编译和开发环境有相应的变化而已。如果涉及Jave方面的编程也是如此的。嵌入式系统中涉及算法的由专业算法的人来处理的,不必归结到嵌入式系统范畴内。但如果涉及嵌入式系统下面嵌入式数据库、基于嵌入式系统的网络编程和基于某此应用层面的协议应用开发(比如基于SIP、H.323、Astrisk)方面又较为复杂,并且有难度了。

篇5:嵌入式Linux系统CGI程序设计技术

来源:单片机及嵌入式系统应用  作者:广东工业大学 郑 伟 徐荣华 王钦若

摘要:在详细介绍一种嵌入式Web服务器BOA的实现与配置方法的基础上,以一个Web在线远程监控GPIO(通用输入/输出)的程序为实例,介绍嵌入式Linux系统下CPU程序设计技术。

关键词:嵌入式系统Linux BOA CGI GPIO

1 概述

随着互联网应用的普及,越来越多的信息化产品需要接入互联网通过Web页面进行远程访问。嵌入式Web系统提供了一种经济、实用的互联网嵌入式接入方案。这里结合一种嵌入式Web Server BOA来介绍嵌入式Linux系统下的CGI程序设计技术。

2 Web Server BOA的实现与配置

2.1 uClinux下,主要有三个Web Server:HTTPD、THTTPD和BOA。HTTPD是最简单的一个Web Server,它的功能最弱,不支持认证,不支持CGI。THTTPD和BOA都支持认证、CGI等,功能都比较全。BOA是一个单任务的小型HTTP服务器,源代码开放、性能优秀,特别适合应用在嵌入式系统中。目前的uClinux的代码中已经包含BOA的源代码。在uClinux下实现BOA,只需要对BOA做一些配置和修改。以下是配置的过程。

(1)编译BOA到内核

首先,需要把BOA编译到内核,即执行make menuconfig,在应用程序选单中network application项下面选择boa。该操作需要重新编译内核。

(2)编制配置文件boa.conf

在Linux操作系统下,应用程序的配置都是以配置文件的形式提供的,一般都是放在目标板/etc/目录下或者/etc/config目录下。但boa的配置文件boa.cont一般都旋转在目标板/home/httpd/目录下。

例如,一个典型的boa.conf文件格式如下:

ServerName Samsung-ARM

DocumentRoot/home/httpd

ScriptAlias/cgi-bin/home/httpd/cgi-bin/

ScriptAlias//home/httpd/

它指定了HTML页面必须放到/home/httpd目录下,cgi外部扩展程序必须放到/home/httpd/cgi-bin目录下。

(3)编译烧写内核

重新编译内核后,通过烧写工具烧写内核,就可以在PC上通过IE浏览器访问开发板上的.Web Server。例如,输入开发板的IP地址192.168.0.101,即可访问到自己做的网页index.html了。并且,通过编写CGI外部扩展程序,可以实现动态Web技术,下面将详细介绍。

2.2 具有MMU平台的Linux下B0A的实现与配置

对于有MMU(内存管理单元)的平台,如armlinux和ppclinux,可以到网上下载一个主流版本的boa发行包。因为是运行在目标系统,所以要用交叉编译工具编译,即需要修改boa/src/Makefile里面的编译器。例如:

CC=/LinuxPPC/CDK/bin/powerpc-linux-gcc

CPP=/LinuxPPC/CDK/bin/powerpc-linux-g++

然后直接在boa/src目录下执行make,即可生成BOA可执行文件;将其编译入内核,并烧写到存储设备,就可以实现访问BOA服务器。

篇6:嵌入式Linux系统CGI程序设计技术

CGI(Common Gateway Interface)是外部应用扩展应用程序与WWW服务器交互的一个标准接口。按照CGI标准编写的外部扩展应用程序可以处理客户端浏览器输入的数据,从而完成客户端与服务器的交互操作。而CGI规范就定义了Web服务器如何向扩展应用程序发送消息,在收到扩展应用程序的信息后又如何进行处理等内容。通过CGI可以提供许多静态的HTML网页无法实现的功能,比如搜索引擎、基于Web的数据库访问等等。

3.1 工作原理

(1)WWW和CGI的工作原理

HTTP协议是WWW的基础,它基于客户/服务器模型,一个服务器可以为分布在网络中处的客户提供服务;它是建立在TCP/IP协议之上的“无连接”协议,每次连接只处理一个请求。在服务器上,运行产着一个守护进程对端口进行监听

,等待来自客户的请求。当一个请求到来时,将创建一个子进程为用户的连接服务。根据请求的不同,服务器返回HTML文件或者通过CGI调用外部应用程序,返回处理结果。服务器通过CGI与外部程序和脚本之间进行交互,根据客户端在进行请求时所采取的方法,服务器会收集客户所提供的信息,并将该部分信息发送给指定的CGI扩展程序。CGI扩展程序进行信息处理并将结果返回服务器,然后服务器对信息进行分析,并将结果发送回客户端。

外部CGI程序与WWW服务器进行通信、传递有关参数和处理结果是通过环境变量、命令行参数和标准输入来进行的。服务器提供了客户端(浏览器)与CGI扩展程序之间的信息交换的通道。CGI的标准输入是服务器的标准输出,而CGI的标准输出是服务器的标准输入。客户的请求通过服务器的标准输出传送给CGI的标准输入,CGI对信息进行处理后,将结果发送到它的标准输入,然后由服务器将处理结果发送给客户端。

(2)URL编码

客户端浏览器向服务器发送数据采用编码的形式进行。该编码就是CRL编码。编码的主要工作是表单域的名字和值的转义,具体的做法为:每一对域和值里的空格都会被替换为一个加号(+)字符,不是字母或数字的字符将被替换为它们的十六进制数字形式,格式为%HH。HH是该字符的ASCII十六进制值。

标签将被替换为“%0D%0A”。

信息是按它们在表单里出现的顺序排列的。数据域的名字和数据域的值通过等号(=)字符连在一起。各对名/值再通过“&”字符连接在一起。经过这些编码处理之后,表单信号就整个成为一个连续的字符流,里面包含着将被送往服务器的全部信息。

因为表单输入信息都是经过编码后传递给脚本程序的,所以CGI扩展程序在使用这些参数之前必须对它们进行解码。

3.2 CGI外部扩展程序编制

服务器程序可以通过三种途径接收信息:环境变量、命令行和标准输入。具体使用哪一种方法要由

它调用的服务器脚本程序是/cgi/bin/cgi_gpio.cgi。CGI扩展程序中FORM表单的解码可参考如下程序:

/*function getPOSTvars*/

char **getPOSTvars{

int i;

int content_length;

char **postvars;

char *postinput;

char **pairlist;

int paircount=0;

chr *nvpair;

char *eqpos;

postinput=getenv(“CONTENT_LENGTH”);//获取传送给程序数据的字节数

if(!postinput)

exit();

if(!content_length=atoi(postinput))) //获取信息长度

exit(1);

if(!(postinput=(char*)malloc(content_length+1)))

exit(1);

if(!fread(postinput,content_length,1,stadin))

exit(1);

postinput[content_length]='0';

for(i=0;postinput[i];i++)

if(postinput[i]=='+')

postinput[i]=''; //对加易进行处理

pairlist=(char **)malloc(256*sizeof(char **));

paircount=0;

nvpair=strtok(postinput,“&”);//从出现“&”字符的位置把信息分段,然后对结果依次处理

while (nvpair){

pairlist[paircount++]=strdup(nvpair);

if(!(paircount%256))

pairlist=(char**)realloc(pairlist,(paircount+256)*sizeof(char**));

nvpair=strtok(NULL,“&”);

}

pairlist[paircount]=0;

postvars=(char**)malloc((paircount*2+1)*sizeof(char **));

for(i=0;i

if(eqpos=strchr(pairlist[i],'=')){

*eqpos='0';

unescape_url(postvars[i*2+1]=strdup(eqpos+1));//调用unescape_url函数继续解码

}else{

unescape_url(postvars[i*2+1])=strdup(“”));

}

postvars[paircount*2]=0;

for(i=0;pairlist[i];i++)

free(pairlist[i]);

free(pairlist);

free(postinput);

return postvars;

}

其中,unescape_url函数再调用x2c函数,把(不是字节或数字的)特殊字符从其%HH表示方式解码为文本字符。

/*unescape_url function*/

static void unescape_url(char *url){

int x,y;

for(x=0,y=0;url[y];++x,++y){

if((url[x]=url[y])=='%'){

url[x]=x2c(&url[y+1]);

y+=2;

}

}

url[x]='0';

}

(3)直接URL加参数传递方法

这是一种不使用表单就可以向CGI传送信息的方法。它把信息直接追加在URL地址后面,信息和URL之间用号号(?)来分隔。例如,对于一个cgi_gpio.cgi的脚本,可以从如下的链接启动:

/*cgi-bin/cgi_gpio.cgi?flag=1 Operate P1

.

.

.

CGI扩展程序中可使用如下代码接收信息:char *get_input;//用于接收环境变量

.

.

.

get_input=getenv(“QUERY_STRING”);

if(get_input){

get_input=strdup(get_input);

printf(“QUERY_STRING if %s”,get_input);

}

/*判断flag=x信息*/

if(!strcmp(get_input,“flag=0”)

...//Operate p0

else if(!strcmp(get_input,“flag=1”)

...//Operate P1

else

...//Operate P2

对于上述三种方法,可以根据不同的应用场合和应用要求进行选取。

结语

嵌入式Web Server系统方案可以广泛应用在许多领域,如自动化设备的远程监控、嵌入式GSM短消息平台以及远程家庭医疗等。并且,随着互联网应用领域的不断深入,嵌入式Internet技术将得到更为广泛的应用和发展。

篇7:嵌入式Linux系统CGI程序设计技术

嵌入式Linux系统CGI程序设计技术

来源:单片机及嵌入式系统应用  作者:广东工业大学 郑 伟 徐荣华 王钦若

摘要:在详细介绍一种嵌入式Web服务器BOA的实现与配置方法的基础上,以一个Web在线远程监控GPIO(通用输入/输出)的程序为实例,介绍嵌入式Linux系统下CPU程序设计技术。

关键词:嵌入式系统Linux BOA CGI GPIO

1 概述

随着互联网应用的普及,越来越多的信息化产品需要接入互联网通过Web页面进行远程访问。嵌入式Web系统提供了一种经济、实用的互联网嵌入式接入方案。这里结合一种嵌入式Web Server BOA来介绍嵌入式Linux系统下的CGI程序设计技术。

2 Web Server BOA的.实现与配置

2.1 uClinux下,主要有三个Web Server:HTTPD、THTTPD和BOA。HTTPD是最简单的一个Web Server,它的功能最弱,不支持认证,不支持CGI。THTTPD和BOA都支持认证、CGI等,功能都比较全。BOA是一个单任务的小型HTTP服务器,源代码开放、性能优秀,特别适合应用在嵌入式系统中。目前的uClinux的代码中已经包含BOA的源代码。在uClinux下实现BOA,只需要对BOA做一些配置和修改。以下是配置的过程。

(1)编译BOA到内核

首先,需要把BOA编译到内核,即执行make menuconfig,在应用程序选单中network application项下面选择boa。该操作需要重新编译内核。

(2)编制配置文件boa.conf

在Linux操作系统下,应用程序的配置都是以配置文件的形式提供的,一般都是放在目标板/etc/目录下或者/etc/config目录下。但boa的配置文件boa.cont一般都旋转在目标板/home/httpd/目录下。

例如,一个典型的boa.conf文件格式如下:

ServerName Samsung-ARM

DocumentRoot/home/httpd

ScriptAlias/cgi-bin/home/httpd/cgi-bin/

ScriptAlias//home/httpd/

它指定了HTML页面必须放到/home/httpd目录下,cgi外部扩展程序必须放到/home/httpd/cgi-bin目录下。

(3)编译烧写内核

重新编译内核后,通过烧写工具烧写内核,就可以在PC上通过

[1] [2] [3] [4] [5]

篇8:用GNU工具开发基于ARM的嵌入式系统

用GNU工具开发基于ARM的嵌入式系统

摘要:介绍如何利用GNU的工具开发基于ARM的嵌入式系统,以及使用编译器、连接器和调试工具的具体方法,为广大嵌入式系统开发人员提供一种低成本的开发手段。

关键词:ARMGNUMC928MX1gccgdbgdbserver

当前,ARM公司的32位RISC处理器,以其内核耗电少、成本低、功能强、特有16/32位双指令集,已成为移动通信、手持计算、多媒体数字消费等嵌入式解决方案的RISC标准,市场占有率超过了75%.多家公司都推出了自己的基于ARM内核的处理器产品,越来越多的开发人员开始了针对ARM平台的开发。通常开发人员需要购买芯片厂商或第三方提供的开发板,还需要购买开发软件,如C编译器或者集成了实时操作系统的开发环境。开发板的价格从数百到上千美元,而编译器、实时操作系统价格更是动辄数千到数万美元。这样,在开发初期,软硬件上的投资就需要上万美元,对于国内大多数开发人员来说,无疑是太贵了。

庆幸的是,GNU所倡导的自由软件给开发者带来了福音。1984年,旨在开发一个类似Unix的,并且是完全免费的完整操作系统和配套工具:GNU系统(发音为“guh-NEW”)。GNU的操作系统和开发工具都是免费的,遵循GNU通用公共许可证(GPL)协议,任何人都可以从网上获取全部的源代码。

除了大家熟知的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摄像头等控制器。作为应用开发的最小系统必须包括RAM(程序运行空间)、Flash(存放目标代码)和串行接口(用于调试和下载程序)。MX1提供了6个片选端(CS0――CS5),内置了SDRAM控制器,数据宽度32位。在笔者的系统中采用了2片8M×16位的SDRAM和2片4M×16位的同步Flash存储器,分别接入数据线的低16位和高16位,如图1所示。

图1中SDRAM接片选端CS2,Flash接片选端CS3,其余为SDRAM/Flash的控制信号。最小系统还包括至少1个串行接口,可以采用MX1内置的UART控制器,图略。

2自举模式

目前,许多嵌入式处理器都提供了自举模式(Bootstrap),供用户写入引导代码。自举模式利用了固化在芯片内部的一段引导程序,当处理器复位时,如果在特定引脚上加信号,则处理器将在复位后执行固化ROM中的程序。例如,MX1提供了4条复位引脚,复位时引脚不同的电平组合可以从不同的片选端启动系统。自举ROM中的程序完成串口的初始化,然后等待用户从串口写入用户代码。自举模式所能接受的是一种专门格式的文本文件,包括数据和要写入/读出的地址。关于自举模式的代码格式,可参考相关芯片的手册。在摩托罗拉的网站还提供了许多小工具,帮助开发者将其它格式的文件转换成为自举模式格式。通过自举模式下载的通常是一段和上位机软件(如超级终端)通信的程序,完成接收数据并写入Flash的操作。写入的数据可以是用户自己的应用程序、数据或者操作系统的内核。通过自举模式下载的引导程序同样可以用GNU工具开发。

3GNU的编译器和开发工具

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开始并执行。完成串口和SD

RAM的初始化后,引导程序将等待接收应用程序或操作系统内核,将接收到的数据放在SDRAM中。数据接收完毕后,引导程序将SDRAM中的数据写入Flash,下一次就可以从Flash中直接引导系统了。由于操作系统的内核比较大,如Linux有1MB以上,下载过程必须考虑纠错。因此,接收部分采用Xmode协议,可以用Windows下超级终端的Xmode发送方式发送文件。

(1)编写C、C++语言或汇编源程序

通常汇编源程序用于系统最基本的初始化,如初始化堆栈指针、设置页表、操作ARM的协处理器等。初始化完成后就可以跳转到C代码执行。需要注意的是,GNU的汇编器遵循AT&T的汇编语法,读者可以从GNU的站点(www点gnu点org)上下载有关规范。汇编程序的缺省入口是start标号,用户也可以在连接脚本文件中用ENTRY标志指明其它入口点(见下文关于连接脚本的说明)。

(2)用gcc或g++生成目标文件

如果应用程序包括多个文件,就需要进行分别编译,最后用连接器连接起来。如笔者的引导程序包括3个文件:init.s(汇编代码、初始化硬件)xmrecever.c(通信模块,采用Xmode协议)和flash.c(Flash擦写模块)。

分别用如下命令生成目标文件:

arm-linux-gcc-c-O2-oinit.oinit.s

arm-linux-gcc-c-O2-oxmrecever.oxmrecever.c

arm-linux-gcc-c-O2-oflash.oflash.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-obootstrap.elf-Tlink.ldsinit.oxmrecever.oflash.o

其中,ostadlib表示不连接系统的运行库,而是直接从begin入口;-o指明目标文件的名称;-T指明采用的连接脚本文件;最后是需要连接的目标文件列表。

(5)生成二进制代码

连接生成的elf文件还不能直接下载执行,通过objcopy工具可生成最终的二进制文件:

arm-linux-objcopy-Obinarybootstrap.elfbootstrap.bin

其中-Obinary指定生成为二进制格式文件。Objcopy还可以生成S格式的文件,只需将参数换成-Osrec.如果想将生成的目标代码反汇编,还可以用objdump工具:

arm-linux-objdump-Dbootstrap.elf

至此,所生成的目标文件就可以直接写入Flash中运行了。如果要通过自举模式下载,还需要转换为自举模式的文件格式,相关转换工具可以在摩托罗拉的网站上找到。

掌握了GNU工具后,开发者就可以开发或移植C或C++代码的程序。用户可以不需要操作系统,直接开发简单应用程序。但对于更复杂的应用来说,操作系统必不可少。目前流行的源代码公开的操作系统如Linux、μC/OS都可以用GNU工具编译。ARM的Linux已有很多成熟的版本,可以支持ARM720、ARM920、ARM1020等多种处理器。

m上获取最新信息。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.

对于Linux内核的调试,可以采用kgdb工具,同样需要通过串口与上位机上的gdb通信,对目标板的Linux内核进行调试。

结束语

本文以一个具体的实例为例,对GNU工具中的常用功能作了介绍。其实GNU工具的功能还远不止这些,更进一步的操作有:针对不同处理器,不同算法的软件优化、高效的内嵌汇编、大型项目管理功能等。相信GNU能成为越来越多开发人员的选择。

篇9:用GNU工具开发基于ARM的嵌入式系统

用GNU工具开发基于ARM的嵌入式系统

摘要:介绍如何利用GNU的工具开发基于ARM的嵌入式系统,以及使用编译器、连接器和调试工具的具体方法,为广大嵌入式系统开发人员提供一种低成本的开发手段。

关键词:ARM GNU MC928MX1 gcc gdb gdbserver

当前,ARM公司的32位RISC处理器,以其内核耗电少、成本低、功能强、特有16/32位双指令集,已成为移动通信、手持计算、多媒体数字消费等嵌入式解决方案的RISC标准,市场占有率超过了75 %。多家公司都推出了自己的基于ARM内核的处理器产品,越来越多的开发人员开始了针对ARM平台的开发。通常开发人员需要购买芯片厂商或第三方提供的开发板,还需要购买开发软件,如C编译器或者集成了实时操作系统的开发环境。开发板的价格从数百到上千美元,而编译器、实时操作系统价格更是动辄数千到数万美元。这样,在开发初期,软硬件上的投资就需要上万美元,对于国内大多数开发人员来说,无疑是太贵了。

庆幸的是,GNU所倡导的自由软件给开发者带来了福音。1984 年,旨在开发一个类似 Unix 的,并且是完全免费的完整操作系统和配套工具:GNU 系统(发音为“guh-NEW”)。GNU的操作系统和开发工具都是免费的,遵循GNU 通用公共许可证 (GPL)协议,任何人都可以从网上获取全部的源代码。关于GNU和公共许可证协议的详细资料,读者可参看GNU网站的中文介绍: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的详细资料,感兴趣的读者可以参考www.motorola.com.cn/semiconductors/。作为应用开发的最小系统必须包括RAM(程序运行空间)、Flash(存放目标代码)和串行接口(用于调试和下载程序)。MX1提供了6个片选端(CS0~CS5),内置了SDRAM控制器,数据宽度32位。在笔者的系统中采用了2片8M×16位的SDRAM和2片4M×16位的同步Flash存储器,分别接入数据线的低16位和高16位,如图1所示。

图1中SDRAM接片选端CS2,Flash接片选端CS3,其余为SDRAM/Flash的控制信号。最小系统还包括至少1个串行接口,可以采用MX1内置的UART控制器,图略。

2 自举模式

目前,许多嵌入式处理器都提供了自举模式(Bootstrap),供用户写入引导代码。自举模式利用了固化在芯片内部的一段引导程序,当处理器复位时,如果在特定引脚上加信号,则处理器将在复位后执行固化ROM中的程序。

[1] [2] [3] [4]

篇10:基于ARM的嵌入式web服务器的设计

基于ARM的嵌入式web服务器的设计

嵌入式系统和internet技术相结合成为一种新兴技术.本文介绍了一种嵌入式web服务器的软硬件的`设计方案,实现了以太网和嵌入式系统的连接,提高了嵌入式系统的远程访问能力.

作 者:尚秀珍  作者单位:济南第五职业中专,山东济南,250011 刊 名:中国科技博览 英文刊名:CHINA SCIENCE AND TECHNOLOGY REVIEW 年,卷(期):2009 “”(12) 分类号:G 关键词:TCP/I   B/S方式   微控制器  

ARM7系统中实现CF卡存储的文件系统设计

实验室建设项目资金申请报告

嵌入式系统的实习报告

嵌入式实习总结

大容量NAND?Flash?TC58DVG02A1F

基于ARM的实时测控系统开发平台

简论CDIO的地方高校嵌入式系统仿真实验室建设研论文

嵌入式产品开发简历表格

模具设计实习报告

新道云实训报告心得体会

基于ARM体系的嵌入式系统BSP的程序设计
《基于ARM体系的嵌入式系统BSP的程序设计.doc》
将本文的Word文档下载到电脑,方便收藏和打印
推荐度:
点击下载文档

【基于ARM体系的嵌入式系统BSP的程序设计(锦集10篇)】相关文章:

模具设计实践报告2023-11-29

嵌入式开发工程师个人简历2023-11-13

软件工程专业大学生个人简历2023-11-14

软件工程专业个人简历2022-06-27

软件工程专业求职个人简历2022-05-08

全国物流师第二次统考试题2022-05-27

大学生月实习报告2022-11-30

实训报告心得体会2022-10-20

卧龙岗大学工程学士的就业方向解析2022-12-17

嵌入式系统低功耗软件技术分析论文2022-11-04

点击下载本文文档