嵌入式软件开发简介

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

火龙果 整理 uml.org.cn
系统启动

系统启动有两个阶段:硬件阶段和软件阶段。


硬件阶段:一旦复位线有效(装电池或按“电源”键), 处理器就进入到硬件阶段。此阶段的主要职责是使CPU开 始运行程序或运行一些要把CPU控制权转交给程序的代码, 程序的最初几行代码定义了如何启动软件。 软件阶段:此阶段的职责是初始化核心元件和内存的关 键结构(用来建立完整的运行时环境)。

系统启动的具体过程与处理器的类型有关。
火龙果 整理 uml.org.cn
系统启动过程举例(Arm微处理器)




从程序的初始入口点处开始运行,这里用ENTRY伪操作标 识程序入口点; 调用复位异常处理中断(如boot_reset_handler)函数; 对存储器和外围控制硬件进行初始化; 执行ROM和RAM有效性校验和测试,如验证ROM中是否包含 一个有效的应用映像; 将已初始化的数据( ROM 中)拷贝到可写的数据区 ( RAM 中),并将剩下的RAM 空间初始化为0; 初始化数据栈指针 调用main()函数开始运行主程序
火龙果 整理 uml.org.cn
中断响应周期

定义:当CPU接收到中断信号,他就把正在做的事情放在 一边,执行处理此中断的指令,然后回到先前的任务。 当某个设备发出中断信号给CPU,CPU将:


把下一条指令(返回地址)的地址压入栈中 从异常向量表加载ISR(中断服务程序)地址到程序计 数器中 禁止中断 恢复运行正常的取指周期,此时取出的是ISR指令

使用IMPORT伪操作声明该全局变量 使用LDR指令读取该全局变量的内存地址 根据该数据的类型,使用相应的LDR指令读取该全局变量的值

使用相应的指令修改该全局变量的值
AREA globals,CODE,READONLY EXPORT asmsub IMPORT global ;用IMPORT伪操作声明该变量 ;将器内存地址读入到寄存器R1中 ; 再将其值读入到寄存器R0中 ;修改后再将寄存器r0的值赋予变量global
编译选项(cont.)
选项名称 -fa 描述 对数据流是否出现异常进行检查 备注 如检查是否一个变量没有 被赋值而被使用 -Wb -Ospace -O2 指定产生警告信息的级别 进行基于缩小代码尺寸(以可能增加 执行时间为代价)的优化。 使用完全优化(fully optimized )的级别 -o file 指定生成的目标文件的名称

火龙果 整理 uml.org.cn
栈帧(StackFrame)


定义:分配给一个函数的所有栈空间(参数、返回地址和局部变量)称 为栈帧 栈被用来存放所有的函数局部变量和参数,函数调用的处理流程如下:

把所有参数压栈 调用函数 为所有局部变量在栈中分配存储空间 执行函数 释放分配给局部变量的栈空间 从函数返回 释放参数所使用的栈空间
火龙果 整理 uml.org.cn
速度和代码密度



在很多情况下,如果是通过指针而不是正常的变量引用执行操作,编译器就能产生 占用空间更少且执行速度更快的代码。 如果某个函数操作某个变量多次,或者逐个访问某个数组的成员变量,通过指针来 进行访问可能会产生更有效率的代码。 如对如下代码: void strcpy2(char dst[],char const src[ ]) {



火龙果 整理 uml.org.cn
内嵌式汇编

如果仅仅需要从特定端口进行读写操作,使用内嵌式汇编是最简单的解决方案。 内嵌式汇编依赖于编译器。使用方式有如下两种: 使用类似_asm/_endasm的特殊标志符; 把汇编语句包装起来,类似函数调用,如asm(“ ”);

ARM ADS1.2 编译器使用第一种方式。其语法如下:
Asmsub
LDR r1,=global LDR r0,[r1] ADD r0,r0,#2 STR r0,[r1] MOV pc,lr END
火龙果 整理 uml.org.cn
C++程序使用 C程序头文件

在C++程序使用 C程序头文件时,必须将用户定义的头文件包含在伪操作extern “C”{ }中,有如下两种方法来完成这种操作: 在C++程序中包含该头文件时,将其放在伪操作extern “C”{ }中。 //c++ code extern “C” { #include “my-cheader1.h” //在C++程序中使用伪操作extern “C”{ } #include “my-cheader1.h” } int main() { //….. return 0; }
以及进行软件栈检查
指令是32位指令(执行速
度快); Thumb指令是16位指令
-littleend
字节排序的方式为 “小端排序”, 如对数值0x2f1d, 第一个
即一个数据字的最小有效位(LSB) 字节存放0x1d; 第二个字
的字节存在最低的地址上 节存放0x2f
火龙果 整理 uml.org.cn
火龙果 整理 uml.org.cn
嵌入式软件开发简介
何耀东
2005/12
火龙果 整理 uml.org.cn
嵌入式软件开发简介



嵌入式系统的特点 嵌入式系统设计的生命周期 执行环境 独特的软件技术 ADS编译器相关知识 编程注意事项
Baidu Nhomakorabea
火龙果 整理 uml.org.cn
嵌入式系统特点
火龙果 整理 uml.org.cn
内存结构



所有静态分配的读/写变量都放在自由内存(RAM数据空 间)中。全局变量是静态分配变量最常见的形式,C语言 中的“static”型变量也放在这里。任何拥有全局生存期 的可修改变量都存放在自由内存中。 所有动态分配(使用new或malloc())的对象和变量都放 在堆中。许多嵌入式系统并没有使用堆。 最后的内存组成部分是映射到内存的外部设备寄存器(如 键盘、显示屏、耳机、光感应器、充电器)。这些设备的 状态放在I/O空间区域。



嵌入式系统一般用于特定的任务 嵌入式系统通常及其关注成本 嵌入式系统有实时约束 嵌入式系统一般用实时操作系统(RTOS) 嵌入式系统大多有功耗约束 嵌入式系统的系统资源有限 嵌入式系统通常在ROM中存放所有目标代码
火龙果 整理 uml.org.cn
嵌入式系统设计生命周期
产品定义(需求分析) 开发计划的制定 软件设计(概要设计和详细设计) 编码及单元测试 硬件和软件集成
__asm {
instruction [; instruction]
... [instruction] } 若两个指令在同一行,则必须用分号隔开。若一条指令分两行显示则必须在行尾加 符号 ‘\’ .
火龙果 整理 uml.org.cn
汇编程序访问C变量

在C程序中声明的全局变量可以被汇编程序通过地址间接访问。具体访问方法如下:
系统测试
产品发布 维护和升级
火龙果 整理 uml.org.cn
执行环境



内存结构 系统启动 中断响应周期 栈帧
火龙果 整理 uml.org.cn
执行环境

内存结构

一般微处理器的内存映像如下图:
代码空间 ROM数据 空间 I/O空间 RAM数据 空间 堆 栈
系统空间
图1 处理器的内存映像
火龙果 整理 uml.org.cn
内存结构




系统空间为存放异常向量表的内存空间。处理器用 异常向量标识出在系统遇到中断或其他异常(比如 被零除、溢出错误、内存操作出错或指令错误)时 将运行哪段代码,进行相应的处理。 在系统空间之上的代码空间存放着指令。一般要把 系统和代码空间存放在同一ROM物理设备中。 在代码空间之上,ROM数据空间存放常量数值,比如 错误信息和其他字符串。 栈用来保存当前运行状态和所有暂停运行的进程的 上下文。因此,栈包含所有局部变量以及函数和中 断的返回地址。只有提供了栈空间,程序才能进行 中断服务或调用函数。栈一般位于内存的高端,即 栈从上向下增长。
armar
建立ARM库文件的工具
火龙果 整理 uml.org.cn
编译选项示例 选项名称 描述 备注
-I"$(ARMINC)" -cpu ARM7TDMI -apcs /interwork
指定搜索包含文件的路径 指定CPU 为 ARM7
C:\apps\include
指 定 过 程 调 用 标 准 ( PCS ) 为 Interwork 指 允 许 混 合 使 interwork 用ARM 和Thumb代码。ARM
火龙果 整理 uml.org.cn
独特的软件技术

控制外设 内嵌式汇编 汇编程序访问C变量 C++程序使用 C程序头文件 内存映射访问 使用存储类限定符volatile 速度和代码密度 中断和中断服务例程(ISRs)
火龙果 整理 uml.org.cn
控制外设

火龙果 整理 uml.org.cn
ADS 工具包(toolkits)

ADS编译器提供如下工具:
工具名称 armcc armcpp armasm armlink FromELF ARM C 编译器 ARM C++编译器 ARM 汇编器 ARM 连接器
功能描述
将连接生成的ARM ELF文件转化为其他格 式的文件(如BIN、 HEX)
嵌入式系统程序员经常需要编写一些直接控制外设的代码(如键盘、lcd、 uim卡、充电器、麦克、speaker等)。对于不同的计算机体系结构,设 备可能是端口映射的,也可能是内存映射的。 如果系统结构支持独立的I/O地址空间,且外设是端口映射的,则必须 用汇编语言完成实际操作,这是由于C语言没有真正的“端口”概念。 对基于内存映射的外设,可通过C语言指针来访问内存映射硬件。通过 简单的强制类型转换操作使指针定位到指定的任意内存地址。如用如下 代码读寄存器的值: unsigned short x; volatile unsigned short * io_regs; io_regs=(unsigned short *) 0x40000000; x=*io_regs[10]; 在ARM中,使用基于内存映射的方式控制外部设备
火龙果 整理 uml.org.cn
火龙果 整理 uml.org.cn
C++程序使用 C程序头文件

在该头文件中使用伪操作extern “C”{ },使得其被C++程序包含时,自动加上 extern “C”{ }。 /* C header file */
#ifdef __cplusplus //如果头文件被C++程序引用
extern “C” { #endif //在头文件中使用伪操作extern “C”{ }
/*头文件实际内容
#ifdef __cplusplus }
*/
#endif
火龙果 整理 uml.org.cn
存储类限定符volatile
大多数编译器为了减小代码尺寸,一般要对代码进行优化; 或者为了获得更高的执行效率,有时可能把内存数据放到数 据高速缓存(CACHE)中。这种方法是基于一个关键性假设: 除非明确地把某值写到内存,否则内存中的值不会改变。 由于硬件外设的寄存器值随时都在变化,为了避免出现问题, 可用关键字volatile来告诉编译器不要使用各种方法对其进 行优化,也不必把它放到数据高速缓存中。

int I; for(I=0;src[I];I++) {

dst[I] = src[I];

}
}
火龙果 整理 uml.org.cn
速度和代码密度(cont.)

转换为汇编指令后,函数长度为34个字节,循环体 有4条指令。

这个循环可以用指针的方式,即:
void strcpy2(char *dst,char const*src) {

while((*dst++ = *src++)) {;}
}


转换为汇编指令后,函数长度为20个字节,循环体 有2条指令。 可以看出,用指针方式既节省了代码空间,又提高 了执行效率。
火龙果 整理 uml.org.cn
ADS编译器相关


ADS 工具包(toolkits) 编译选项示例 结构和域的对齐
相关文档
最新文档