基于ARM的嵌入式程序开发要点.pdf

所需积分/C币:9 2007-04-02 15:44:15 600KB PDF
14
收藏 收藏
举报

基于ARM的嵌入式程序开发要点
基于ARM的嵌入式程序开发要点 ●符合目标系统上的存储器资源分布 应用程序运行环境的初始化 2.开发工具环境里面的库函数 如果用户程序里调用了跟目标相关的一些库喲数,则在应用前需要裁剪这些 函数以适合在目标上允许的要求。主要需要考虑以下三类函数: ●访问静态数据的函数 ●访问目标存储器的函数 使用 semihosting(半主机)机制实现的函数 这里所指的C库函数,除了lSOC标准里面定义的函数以外,还包括由编 译工具提供的外一些扩展函数和编译辅助函数。 2.1裁剪访问静态薮据的函数 库函数里面的静态数据,基本上都是在头文件里面加以定义的。比如 CTYPE 类库函数,其返冋值都是通过预定义好的 CTYPE属性表来获得的。比如,想要 改变 igalpha)函数的缺省判断,则需要修改对应 CTYPE属性表里对字符属性的 定义。 2.2裁减访问目标存储器的函数 有一类动态内存管理函数,如mloc(O等,其本身是独立于目标系统而运行 的;但是它所使用的存储器空间需要根据目标来确定。所以 malloch函数本身 并不需要裁剪或移植,但那些设置动态内存区(地址和空间)的函数则是跟目标 系统的存储器分布直接相关的,需要进行移植。例如堆栈的初始化函数 user initial stackheapo,是用来设置堆(heap)和栈( stack)地址的函数,显 然针对每一个具体的目标平台,该函数都需要根据具体的目标存储器资源进行正 确移植。 下面是对示例函数 user initial stackheapo进行移植的一个例子: value in regs struct initial stackheap user initial stackheap unsigned RO, unsigned SP, unsigned R2, unsigned SL) struct initial stackheap config config.heap base=(unsigned int)Ox11110000 ∥ config. stack base=SP //optional return config: ARM-CHINA-040415A 本文档由一维电子收集整理(ww.ueone.com) 基于ARM的嵌入式程序开发要点 请注意上面的函数体并不完全遵循标准C的关键字和语法规范,使用了ARM 公司编译器(ADS或 Real view Compilation tool)里的C语言扩展特性。关于编译 器特定的C语言扩展,请参考相关的编译器说明,这里简单介绍函数 uscr initial stackhcapo的功能,它主要是返回堆和栈的基地址。上面的程序中 只对堆(heap)的基地址进行了设置(设成了0x111000也就是说用广把 0x11100始的存储器地址用作了动态内存分配区(heap区)。具体地址的确 定是要由用户根据自己的目标系统和应用情况来确定的,至少要满足以下条件: ●0x111100始的地址空间有效且可写(是RAM) ●该存储器空间不与其它功能区冲突(比如代码区、数据区、 stack区等) 因为_ user initial stackheap(函数的全部执行效果就是返回些数值,所 以只要符合接口的调用标准,直接用汇编来实现看起来更加直观一些: EXPORT user initial stackheap user initial stackheap LDRr0,0x11110000 MOV lr 如果不对这个函数进行移植,编译过程中将使用缺省的设置,这个设置适用 于ARM公司的 Integrator系列平台。 (注意:ARM的编译/连接工具链也提供了绕过库凶数来设置运行时存储器模型 的方法,请参阅ARM公司其他的相关文档。) 2.3裁剪使用 semihosting(半主机)机制实现的函数 库函数里有一大部分函数是涉及到输入/输出流设备的,比如文件操作函数需 要访问磁盘ⅠO,打印函数需要访问字符输出设备等。在嵌入式调试环境下,所 有的标准C库函数都是有效且有其缺省行为的,很多日标系统使件不能支持的 操作,都通过调试工具米完成了。比如pint0函数,缺省的输出设备是调试器 里面的信息输出窗口。 但是一个真实的系统是需要脱离调试工具而独立运行的,所以在程序的移植 过程当中,需先对这些库函数的运行机制作一了解。 下图说明了在ADS下面这类C库函数的结构 ARM-CHINA-040415A 本文档由一维电子收集整理(ww.ueone.com) 基于ARM的嵌入式程序开发要点 应用程序调用的 ANSIC 函数,如 printf printf( C库函数 设备驱动程序级 Input/ Error Stack Other 使用 semihosting output handling heap setup 机制 如_ sys write 调试辅助坏境 Semihosting Support 由调试系统执行 图-3:C库函数实现过程中的层次调用 如图中例子所示,函数 printf()最终是调用了底层的输入/输出函数 s write()来实现输出操作的,而 sys write()使用了调试工具的内部机制来把 信息输出到调试器 显然这样的函数调川过程在一个真实的嵌入式系统里是无法实现的,因为独 立运行的嵌入式系统将不会有调试器的参与。如果在最终系统屮仍然要保留 print()函数,而且在系统硬件中具备止确的输出设备(如LCD等),则在移植 过程中,需要把 printi)调用的输出设备进行重新定向。 考察prnt(函数的完整调川过程: printf fput(o sys witco 输出设备 其他函数 其他函数 图-4: printi)的调用过程 单纯考虑 printf的输出重新定向,可以有三种途径实现 令改写 printf0)本身 ◆改写fut( 令改写 sys write(O 需要注意的是,越底层的函数,被其他上层函数调用的可能性越大,改变了 个底层函数的实现,则所有调用该函数的上层函数的行为都被改变 以fpυutcO的重新实现为例,下面是改变 fusco输出设备到系统串行通信端 的实例: int fputc(int ch, FILE*f) ARM-CHINA-040415A 本文档由一维电子收集整理(ww.ueone.com) 基于ARM的嵌入式程序开发要点 3 / e.g. write a character to an UART s/ char tempeh=ch sendchar(&tempeh); //UART driver return ch; 代码中的函数 sendcharo假定是系统的串口设备驱动函数。只要新建函数 fpuO的接凵符合标准,经过编译连接后,该函数实现就覆盖了原来缺省的函数 体,所有对该函数的调用,其行为都被新实现的函数所重新定向了。 具体哪些库函数是跟目标相关的,这些函数之间的相互调用关系等,请参考 具体的编译器说明 3. Scmihosting(半主机)机制 上面提到许多库函数在调试环境下的实现都调用了一种叫 semihosting的机 制。 Semihosting具体来讲是指一种让代码在ARM目标上运行,但使用运行了 ARM调试器的主机上IO设备的方法;也就是让ARM目标将输入/输出请求 从应用程序代码传递到运行调试器的主机的一种机制。通常这些输入/输出设备 包括键盘、屏幕和磁盘IO。 半主机由一组已定义的SwI操作来实现。库函数调用相应的SwI(软件中 断),然后调试代理程序处理SwI异常,并提供所需的与主机之间的通讯。 printf("Hello world!n”);应用程序代码 目标 printf SWI C库代码 调试器 与运行在主机上的调试器通信 主机 Hello world! 主机屏幕上显小的文本 图-5: Semihosting的实现过程 多数情况下,半主机SWI是由库函数内的代码调用的。但是应用程序也可 以直接调用半主机SWI。半主机SWI的接口函数是通用的。当半主机操作在硬 件仿真器、指令集仿真器、 Realmonitor或 Angel下执行时,不需要进行移植处 理 使用单个SWI编号诮求半主机操作。其它的SWI编号可供应用程序或操 ARM-CHINA-040415A 本文档由一维电子收集整理(ww.ueone.com) 基于ARM的嵌入式程序开发要点 作系统使用。用于半主机的SWI号是 在ARM状态下:0x123456 在Thmb状态下:0xAB SWI编号向调试代理程序指小该SⅥI请求是半主机请求。要辨别具体的操 作类型,用寄存器r0作为参数传递。r0传递的可用半主机操作编号分配如下: ●0x00-0x31:这些编号由ARM公司使用,分别对应32个具体的执行函 数 0x320xFF:这些编号由ARM公司保留,以备将来用作函数扩展 0x100-0x1FF:这些编号保留给用户应用程序。但是,如果编写自己的 sWⅠ操作,建议直接使用SWI指令和SWl编号,而不要使用半主机 SWI编号加这些操作类型编号的方法。 ●0x200-0 XFFFFFFFF:这些编号未定义。当前未使用并且不推荐使用这 些编 半主机SWI使用的软件中断编号也可以由用户自定义,但岩是改变了缺省 的软中断编号,需要: 更改系统中所有代码(包括库代码)的半主机SWT调用 重新配置调试器对半主机请求的捕捉与相应 这样才能使川新的SWI编号 有关半主机SWI处理函数实现的更详细信息,请参考ARM编译器的相关 文档。 4.应用环境的初始化和根据目标系统资源进行的移植 在下一期中介绍应用环境和日标系统的初始化。 ARM-CHINA-040415A 本文档由一维电子收集整理(ww.ueone.com) 基于ARM的嵌入式程序开发要点 基于ARⅥ的嵌入式系统程序开发要点(二) 系统的初始化过程 基于ARM的芯片多数为复杂的片1:系统集成(SoC),这种复杂的系统里多 数的硬件模块都是可配置的,需要由软件来设置其需要的工作状态。因此在用户 的应用程序启动之前,需要有专门的一段启动代码来完成对系统的初始化。由于 这类代码直接面对处理器内核和硬件控制器进行编程,一般都使用汇编语言。系 统启动程序所执行的操作跟具休的目标系统和丌发系统相关,一般通用的内容包 括 ●中断向量表 ●初始化存储器系统 初始化堆栈 初始化有特殊要求的端口、设备 初始化应用程序执行环境 收变处理器模式 呼叫主应川程序 1.中断向量表 ARM要求中断向量表必须放置在从0地址丌始,连续8×4字节的空间内 (ARM720T和ARM9/10及以后的ARM处理器也支持从0 XFFFF0000开始的高 地址向量表,在本文的其他地方对此不再另加说明)。各个屮断欠量在向量表中 的位置分配如下图: OxIC FIC 外部快速中断 0x18 Q 普通外部中断 0x14 (Reserved) 保留 0x10 Data abort 数据异常 OxO Prefetch abort 指令预取异常 0x08 Software Interrupt软件中断 0x04 Undef 未定义指令中断 0x00 Reset 复位中断 图1:中断向量表 每当一个中断发生以后,ARM处理器便强制把PC指针冒为向量表中对应中 ARM-CHINA-040415A 本文档由一维电子收集整理(ww.ueone.com) 基于ARM的嵌入式程序开发要点 断类型的地址值。因为每个中断只占据向量表中1个字的存储器空间,只能放置 1条ARM指令,所以通常在向量表中放的是跳转指令,使程序能从向量表里跳 转到储器甲的其他地方,再执行中断处理。 中断向量表的程序实现通常如下所示: ARea Boot CODE READONLY ENTRY b Resct handler Resct handler is a labcl b Undef Handler b SWI Handler b Preabort handler b Data abort handler B for reserved interrupt stop here B IRO Handler B FIQ Handler 其中的关键字 ENTRY是指定编译器保留这段代码,因为编译器可能会认为 这是一段冗余代码而加以优化。连接的时候要确保这段代码被链接在0地址处, 并且作为整个程序的入口点(关键字 ENTRY并非总是用来设置程序入口点,所 以通常需要在连接选项里显式地指定程序入口点)。 2.初始化存储器系统 初始化存储器系统的编程对象是系统的存储器控制器。存储器控制器并不是 ARM内核的部分,不同的系统设计不尽相同,所以应该针对具体的要求来 完成这部分的程序设计。一般来说,下面这两个方面是比较通用的。 存储器类型和时序配置 一个复杂的系统可能存在多种存储器类型的接凵,需要根据实际的系统设计 对此加以正确配置。对同一种存储器类型来说,也因为访问速度的差异,需要不 同的时序设置。 通常 Flash和SRAM同属于静态存储器类型,可以合用同一个存储器端口; 而DRAM因为动态刷新和地址线复用等特性,通常配有专用的存储器端凵 存储器端口的接口时序优化是非常重要的,影响到整个系统的性能。因为 般系统运行的速度瓶颈都存在于存储器访问,所以存储器访问时序应尽可能地 快;但同时又要考虑由此带来的稳定性问题。只有根据具体选定的芯片,进行多 次的测试之后,才能确定最佳的时序配置。 2.2.存储器地址分布( memory map) ARM-CHINA-040415A 本文档由一维电子收集整理(ww.ueone.com) 基于ARM的嵌入式程序开发要点 有些系统具有非常灵活的存储器地址分配特性,进行存储器初始化设计的时 候一定要根据应用程序的具体要求来完成地址分配 种典型的情况是启动ROM的地址重映射( remap)。如前面第1节所述, 当一个系统上电后程序将自动从0地址处开始执行,因此在系统的初始状奁,必 须保证在0地址处存在正确的代码,即要求0地址开始处的存储器是非易性的 ROM或Fash等。但是因为R○M或 Flash的访问速度相对较慢,每次中断发生 后都要从读取ROM或Fash上面的向量表开始,影响了中断响应速度。因此有 的系统便提供一和灵活的地址重映射方法,可以把0地址重新指向到RAM中去 在这种地址映射的变化过程当中,程序员需要仔细考虑的是程序的执行流程不能 被这种变化所打断。比如下面这种情况: Flash RAM remap 0x0204 (remap 0xD200 0x0200 0x0100 (boot code (Reset Handler Vcctor tablc b Reset handley 0x0000 图2:启动ROM的地址重映射对程序执行流程的影响 系统上电后从 Flash内的0地址开始执行,启动代码位于地址0x100开始的 空间,当执行到地址0x200时,完成了一次地址的重映射,把原来0开始的地址 空间由 Flash转给了RAM。接下去执行的指令(这里为了简化起见,忽略流水 线指令预取的模型)将来自从0x204开始的RAM空间。如果预先没有对RAM 内容进行正确的设置,则里面的数据都是随机的,这样处理器在执行完0x200 地址处的指令之后,再往下取指执行就会出错。解决的方法就是要使RAM在使 川之前准备好正确的内容,包括开头的向量表部分。 有的系统不具备存储器地址重映射的功能,所有的空间地址就相对简单 些,不需要考虑这方面的问题 3.初始化堆栈 因为ARM处理器有7种执行状态,每一种状态的堆栈指针寄存器(SP)都 ARM-CHINA-040415A 本文档由一维电子收集整理(ww.ueone.com)

...展开详情
试读 45P 基于ARM的嵌入式程序开发要点.pdf
立即下载
限时抽奖 低至0.43元/次
身份认证后 购VIP低至7折
一个资源只可评论一次,评论内容不能少于5个字
您会向同学/朋友/同事推荐我们的CSDN下载吗?
谢谢参与!您的真实评价是我们改进的动力~
上传资源赚钱or赚积分
最新推荐
基于ARM的嵌入式程序开发要点.pdf 9积分/C币 立即下载
1/45
基于ARM的嵌入式程序开发要点.pdf第1页
基于ARM的嵌入式程序开发要点.pdf第2页
基于ARM的嵌入式程序开发要点.pdf第3页
基于ARM的嵌入式程序开发要点.pdf第4页
基于ARM的嵌入式程序开发要点.pdf第5页
基于ARM的嵌入式程序开发要点.pdf第6页
基于ARM的嵌入式程序开发要点.pdf第7页
基于ARM的嵌入式程序开发要点.pdf第8页
基于ARM的嵌入式程序开发要点.pdf第9页

试读结束, 可继续读5页

9积分/C币 立即下载