当前位置:首页 > 嵌入式 > 嵌入式教程
[导读]ARM处理器的分散加载及特殊应用研究

摘要 从ARM ELF目标文件主要构成出发,详细介绍了分散加载的基本原理、分散加载文件的语法、分散加载时连接器生成的预定义符号及要重新实现的函数等;以定位目标外设和定义超大型结构体数组两项应用来加以说明,并给出完整的工程实例和Bootloader代码。这些都已经在实际工程中多次应用和验证,是笔者实际工程项目的萃取。
关键词 分散加载 嵌入式系统 Scatter Loading Bootloader ARM ELF


引 言
    在当今的嵌入式系统设计中,ARM处理器以价格便宜、功耗低、集成度高、外设资源丰富和易于使用的特点而得到广泛的应用;在速度和性能方面已达到或超过部分PC104嵌入式计算机的性能,而成本却比相应的PC104计算机低很多,广泛应用于手机、GPS接收机、地图导航、路由器、以太网交换机及其他民用和工业电子设备。
    在一个采用ARM处理器的实时嵌入式系统中,目标硬件常常由Flash、SRAM、SDRAM和NVRAM(非易失性RAM)等存储器组成,并定位于不同的物理地址范围,那么,怎样通过软件更好地访问和利用这些不同的存储器并让系统高效地运行?分散加载(scatter loading)就提供了这样一种机制。它可以将内存变量定位于不同的物理地址上的存储器或端口,通过访问内存变量即可达到访问外部存储器或外设的目的;同时通过分散加载,让大多数程序代码在高速的内部RAM中运行,从而使得系统的实时性大大增强。


1 ARM ELF目标文件的主要构成
    ARM ELF(Executable and Linking Format)目标文件主要由.Text段、.Data段、.BSS段构成,其他段如.debug段、.comment段等与本文关系不大,不作介绍。
    .Text段由可执行代码组成,段类型为Code,属性为RO;
    .Data段由已初始化数据组成,段类型为Data,属性为RO;
    .BSS段由未初始化数据组成,段类型为Zero,属性为RW,在应用程序启动时对该段的数据初始化为零。如果在分散加载文件中指定了UNINIT属性,则在应用程序启动时不初始化该段。


2 分散加载的基本原理
    假设一个采用ARM处理器的实时嵌入式系统目标硬件的存储器由ROM存储器和RAM存储器组成。当一个嵌入式系统在仿真环境下调试完毕,需要脱机运行的时候,就需要将源程序编译连接成可执行目标代码并烧写到ROM存储器中。由于ROM存储器存取数据的速率比RAM存储器慢,因此,让程序在ROM存储器中运行。CPU每次取指令和取数据操作都要访问ROM存储器,这样需要在CPU的总线周期中插入等待周期,通过降低总线的速率来满足访问慢速的ROM存储器,这样势必会降低CPU的运行速率和效率,因此,分散加载就显得非常必要。
    ARM的连接器提供了一种分散加载机制,在连接时可以根据分散加载文件(.scf文件)中指定的存储器分配方案,将可执行镜像文件分成指定的分区并定位于指定的存储器物理地址。这样,当嵌入式系统在复位或重新上电时,在对CPU相应寄存器进行初始化后,首先执行ROM存储器的Bootloader(自举)代码,根据连接时的存储器分配方案,将相应代码和数据由加载地址拷贝到运行地址,这样,定位在RAM存储器的代码和数据就在RAM存储器中运行,而不再从ROM存储器中取数据或取指令,从而大大提高了CPU的运行速率和效率。分散加载的基本原理如图1所示。

3 分散加载文件语法[!--empirenews.page--]
    在一个实时嵌入式系统中,分散加载文件是对目标硬件中的多个存储器块的分块描述,它直接对应目标硬件存储器的起始地址和范围。同时,它在应用程序连接时用于告诉连接器用户程序代码和数据的加载地址和运行地址,在连接时由连接器产生相应的加载地址和运行地址符号,包括代码和数据的加载起始地址、运行地址和长度等。这些符号用于上电后执行启动代码的数据拷贝工作,启动代码根据这些符号,将指定代码和数据由ROM中的加载地址拷贝到RAM中的运行地址中,从而实现代码在高速RAM存储器中的脱机运行。其语法格式如下:

   
    注意:
    ①每一个分散加载文件必须至少包含一个根区,每个根区的加载地址等于执行地址。
    ②每一个引导区必须至少包含一个执行区,每一个执行区必须至少包含一个代码段或数据段;一个引导区可以包含几个执行区,每一个执行区只能属于一个引导区。


4 分散加载时连接器生成的预定义符号
    在编译连接时如果指定了分散加载文件(.scf文件),在连接后会自动生成如下变量:

   
5 重新实现_user_initial_stEickheap()函数
    分散加载机制提供了一种指定代码和静态数据布局的方法。使用分散加载时,必须重新放置堆栈和堆。
    应用程序的堆栈(stack)和堆(heap)是在C库函数初始化过程中建立起来的,在ADSl.2或更新版本中,在缺省状态下C库函数初始化代码会将连接器生成的符号Image$$ZI$$Limit地址作为堆的基地址。在分散加载时,连接器会将用户的__user_initidl_stackheap()函数代替C库函数默认的堆栈和堆初始化函数,并将其连接到用户的镜像文件中,用户可通过重新实现__user_initial_stackheap()函数来改变堆栈和堆的位置,从而适合自己的目标硬件。

    __user_initial_stackheap()可以用C或汇编语言来实现。它必须返回如下参数:

    r0—堆基地址;

    r1—堆栈基地址;

    r2—堆长度限制值(需要的话);

    r3—堆栈长度限制值(需要的话)。
    当用户使用分散加载功能的时候,必须重新实现一user_initial_staacklaeap(),否则连接器会报错:
    Error:L6218E:Undefined symbol Imager$$ZI$$一Limit(referred from sys_stackheap.o)。
    注:Image$$ZI$$Limit变量为零初始化段(ZI段)的末地址。未使用分散加载时,堆默认就定位在ZI段的末地址,如图2所示。

[!--empirenews.page--]

    __user_initial_stackheap()函数的实现有两种方法。
    (1)共用一个存储区
    汇编语言如下:

    
    这种方式定义的堆栈和堆共用一个存储区,采用相向的增长方向,如图3所示。

    (2)使用两个存储区
    汇编语言如下:

   
    这种方式定义的堆栈和堆分别采用两个不同存储区。堆栈采用向下增长,从地址Ox40000到地址Ox20000;堆采用向上增长,从地址0x28000000到地址0x28080000,如图4所示。

6 特殊应用[!--empirenews.page--]
6. 1 定位目标外设
    使用分散加载,可以将用户定义的结构体或代码定位到指定物理地址上的外设,这种外设可以是定时器、实时时钟、静态SRAM或者是两个处理器间用于数据和指令通信的双端口存储器等。在程序中不必直接访问相应外设,只需访问相应的内存变量即可实现对指定外设的操作,因为相应的内存变量定位在指定的外设上。这样,对外设的访问看不到相应的指针操作,对结构体成员的访问即可实现对外设相应存储单元的访问,让程序员感觉到仿佛没有外设,只有内存。
    例如,一个带有两个32位寄存器的定时器外设,在系统中的物理地址为Ox04000000,其C语言结构描述如下:

   
    要使用分散加载将上述结构体定位到Ox04000000的物理地址,可以将上述结构体放在一个文件名为timer_regs.c中,并在分散加载文件中指定即可,如下:


    属性UNINIT是避免在应用程序启动时对该执行段的ZI数据段初始化为零。
    在程序连接后,通过Image map文件可查看该ZI数据段的存储器分配情况:
    Execution Region TIMER(Base:Ox04000000,Size:0x00000008,Max:0xffffffff,ABSOLUTE,UNINIT)Base Addr Size Type Attr Idx E Section Name 0bi ectOx04000000 0x00000008 Zero RW 32.bss tlmer_regs.o从Image map文件可以看出,该TIMER执行区定位在物理地址0x04000000,即结构体timer_regs定位在Ox04000000,因此,在程序中对结构体的操作即是对定时器的操作。
6.2 定义超大型结构体数组
    分散加载机制在提供将指定代码和数据定位在指定物理地址的能力的同时,也提供了一种代码分割机制——可以将指定的零初始化段(ZI段)从可执行代码中分离出来。这样最终生成的烧入ROM或Flash中的镜像文件就不包括那部分分割了的零初始化段,即使该零初始化段再大,也不影响最终生成的镜像文件的大小。但不采用分散加载机制,零初始化段在编译连接后是直接生成到镜像文件中的。它的大小直接影响最终要烧写的文件的大小,且零初始化段的大小还取决于内存的大小,它不能大到超过内存的大小;而采用分散加载机制,可以将某个零初始化段定位到非内存地址的一个存储器外设上,如NVRAM(非易失性随机存储器)。
    笔者曾在一个实际工程中采用这种分散加载机制,将一个2MB的结构体数组定位到外部NVRAM中,用于记录设备在工作过程中采集到的数据;而在本系统中,ARM处理器的内存只有256 KB,Flash存储器也只有2 MB。如果不采用分散加载,程序根本无法运行,也不能烧写到Flash中。
    采用分散加载,把对复杂外设的访问变成对结构体数组的访问,使程序代码精简易懂。对程序员来说,对结构体数组的操作还是和内存变量的操作一样的。
    编者注:本文为期刊缩略版,全文见本刊网站www.mesnet.com.cn。


结 语
    分散加载是嵌入式系统应用中不可或缺的一种加载方式,ARM、DSP、PowerPC和MIPS等嵌入式处理器,都离不开分散加载。这种分散加载的思想是通用的,只是不同处理器的实现方式不同。
    本文详细阐述了基于ARM处理器的分散加载方法及其特殊应用,并以实际工程为例来说明怎样实现分散加载及使用分散加载的好处。它是笔者在实际工程应用中的心得体会,同时也是笔者工作经验的总结,希望本文对从事嵌入式系统设计和应用的工程技术人员能有所帮助。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭