您的位置 首页 IOT

ARM的发动方法

基于ARM的芯片多数为复杂的片上系统,这种复杂系统里的多数硬件模块都是可配置的,需要由软件来设置其需要的工作状态。因此在用户的应用程序

依据ARM的芯片大都为杂乱的片上体系,这种杂乱体系里的大都硬件模块都是可装备的,需求由软件来设置其需求的作业状况。因而在用户的应用程序之前,需求由专门的一段代码来完结对体系的初始化。因为这类代码直接面临处理器内核和硬件控制器进行编程,一般都是用汇编语言。一般通用的内容包含:

中止向量表
初始化存储器体系
初始化仓库
初始化有特殊要求的断口,设备
初始化用户程序履行环境
改动处理器形式
呼叫主应用程序
中止向量表
ARM要求中止向量表有必要放置在从0地址开端,接连8X4字节的空间内。
每逢一个中止产生今后,ARM处理器便强制把PC指针置为向量表中对应中止类型的地址值。因为每个中止只占有向量表中1个字的存储空间,只能放置一条ARM指令,使程序跳转到存储器的其他地方,再履行中止处理。
中止向量表的程序完结一般如下表明:
AREABoot,CODE,READONLY
ENTRY
B  ResetHandler
B  UndefHandler
B  SWIHandler
B  PreAbortHandler
B  DataAbortHandler
B  IRQHandler
B  FIQHandler
其间关键字ENTRY是指定编译器保存这段代码,因为编译器或许会以为这是一段亢余代码而加以优化。链接的时分要确保这段代码被链接在0地址处,而且作为整个程序的进口。
初始化存储器体系
存储器类型和时序装备
一般Flash和SRAM同归于静态存储器类型,能够合用同一个存储器端口;而DRAM因为有动态刷新和地址线复用等特性,一般配有专用的存储器端口。
存储器端口的接口时序优化是非常重要的,这会影响到整个体系的功用。因为一般体系运转的速度瓶颈都存在于存储器拜访,所以存储器拜访时序应尽或许的快;而一起又要考虑到由此带来的安稳性问题。
存储器地址散布
一种典型的状况是发动ROM的地址重映射。
初始化仓库
因为ARM有7种履行状况,每一种状况的仓库指针寄存器(SP)都是独立的。因而,对程序中需求用到的每一种形式都要给SP界说一个仓库地址。办法是改动状况寄存器内的状况位,使处理器切换到不同的状况,让后给SP赋值。留意:不要切换到User形式进行User形式的仓库设置,因为进入User形式后就不能再操作CPSR回到其他形式了,或许会对接下去的程序履行形成影响。
这是一段仓库初始化的代码示例,其间只界说了三种形式的SP指针:
MRS R0,CPSR
BIC  R0,R0,#MODEMASK 安全起见,屏蔽形式位以外的其他位
ORR R1,R0,#IRQMODE
MSR CPSR_cxfs,R1
LDR SP,=UndefStack

ORR R1,R0,#FIQMODE
MSR CPSR_cxsf,R1
LDR SP,=FIQStack

ORR R1,R0,#SVCMODE
MSR CPSR_cxsf,R1
LDR SP,=SVCStack

初始化有特殊要求的端口,设备
初始化应用程序履行环境。一个ARM映像文件由RO,RW和ZI三个段组成,其间RO为代码段,RW是已初始化的全局变量,ZI是未初始化的全局变量。映像一开端总是存储在ROM/Flash里边的,其RO部分即能够在ROM/Flash里边履行,也能够转移到速度更快的RAM中履行;而RW和ZI这两部分是有必要转移到可写的RAM里去。所谓应用程序履行环境的初始化,便是完结必要的从ROM到RAM的数据传输和内容清零。
下面是在ADS下,一种常用存储器模型的直接完结:

编译器运用下列符号来记载各段的开端和完毕地址:
|Image$$RO$$Base| :RO段开端地址
|Image$$RO$$Limit| :RO段完毕地址加1
|Image$$RW$$Base| :RW段开端地址
|Image$$RW$$Limit| :ZI段完毕地址加1
|Image$$ZI$$Base| :ZI段开端地址
|Image$$ZI$$Limit| :ZI段完毕地址加1
这些标号的值是依据链接器中设置的中ro-base和rw-base的设置来核算的。
初始化用户履行环境主要是把RO、RW、ZI三段仿制到指定的方位。

调用主应用程序
当一切的体系初始化作业完结之后,就需求把程序流程转入主应用程序。最简略的一种状况是:
IMPORT main
B????? main
LDR  r0,=|Image$$RO$$Limit|得到RW数据源的开端地址
LDR  r1,=|Image$$RW$$Base|RW区在RAM里的履行区开端地址
LDR  r2,=|Image$$ZI$$Base| ZI区在RAM里边的开端地址
CMP  r0,r1        比较它们是否持平
   BEQ  %F1
0  CMP  r1,r3
   LDRCC r2,[r0],#4

STRCC r2,[r1],#4
   BCC  %B0
1  LDR  r1,=|Image$$ZI$$Limit|
   MOV r2,#0
2  CMP  r3,r1
   STRCC r2,[r3],#4
   BCC  %B2
程序完结了RW数据的仿制和ZI区域的清零功用。其间引用到的4个符号是由链接器榜首输出的。
|Image$$RO$$Limit|:表明RO区末地址后边的地址,即RW数据源的开端地址
|Image$$RW$$Base|:RW区在RAM里的履行区开端地址,也便是编译器选项RW_Base指定的地址
|Image$$ZI$$Base|:ZI区在RAM里边的开端地址
|Image$$ZI$$Limit|:ZI区在RAM里边的完毕地址后边的一个地址
程序先把ROM里|Image$$RO$$Limt|开端的RW初始数据仿制到RAM里边|Image$$RW$$Base|开端的地址,当RAM这边的方针地址抵达|Image$$ZI$$Base|后就表明RW区的完毕和ZI区的开端,接下去就对这片ZI区进行清零操作,直到遇到完毕地址|Image$$ZI$$Limit|

改动处理器形式
因为在初始化过程中,许多操作需求在特权形式下才干进行(比如对CPSR的修正),所以要特别留意不能过早的进入用户形式。
内核级的中止使能也能够考虑在这一步进行。假如体系中别的存在一个专门的中止控制器,这么做总是安全的。
呼叫主应用程序
当一切的体系初始化作业完结之后,就需求把程序流程转入主应用程序。最简略的一种状况是:
IMPORTmain


B   main
直接从发动代码跳转到应用程序的主函数进口,当然主函数姓名能够由用户随意界说。
在ARMADS环境中,还别的供给了一套体系级的呼叫机制。
IMPORT__main

B  __main
__main()是编译体系供给的一个函数,担任完结库函数的初始化和初始化应用程序履行环境,最终主动跳转到main()函数。

了解发动代码(ADS)
所谓发动代码,便是处理器在发动的时分履行的一段代码,主要任务是初始化处理器形式,设置仓库,初始化变量等等.因为以上的操作均与处理器体系结构和体系装备密切相关,所以一般由汇编来编写.
详细到S64,发动代码分红两部分,一是与ARM7TDMI内核相关的部分,包含处理器各反常向量的装备,各处理器形式的仓库设置,如有必要,仿制向量到RAM,以便remap之后处理器正确处理反常,初始化数据(包含RW与ZI),最终跳转到Main.二是与处理器外部设备相关的部分,这和厂商的联络比较大.尽管都采用了ARM7TDMI的内核,可是不同的厂家整合了不同的片上外设,需求不同的初始化,其间比较重要的是初始化WDT,初始化各子体系时钟,有必要的话,进行remap.这一部分与一般控制器的初始化相似,因而,本文不作要点描绘.
在进行剖析之前,请承认如下相关概念:
S64片上FLASH开端于0x100000,共64kB,片上RAM开端于0x200000,共16kB.
S64复位之后,程序会从0开端履行,此刻FLASH被映射到0地址,因而,S64能够获得指令并履行.明显,此刻仍是驻留在0x100000地址.假如运用remap指令,将会把RAM映射到0地址,相同的这时0地址的内容也仅仅RAM的镜像.
S64的FLASH能够确保在最差状况时以30MHz进行单周期拜访,而RAM能够确保在最大速度时的单周期拜访.
OK,以下开端剖析发动代码.

一,处理器反常
S64将反常向量至于0地址开端的几个直接,这些是必需求处理的.因为复位向量坐落0,也需求一条跳转指令.详细代码如下:
RESET
B SYSINIT ; Reset
B UDFHANDLER ; UNDEFINED
B SWIHANDLER ; SWI
B PABTHANDLER ; PREFETCH ABORT
B DABTHANDLER ; DATA ABORT
B . ; RESERVED
B VECTORED_IRQ_HANDLER
B . ; ADD FIQ CODE HERE

UDFHANDLER
B .

SWIHANDLER
B .

PABTHANDLER
B .

DABTHANDLER
B .

请留意,B指令经汇编后会替换为当时PC值加上一个修正值(+/-),所以这条指令是代码方位无关的,也便是不论这条指令是在0地址仍是在0x100000履行,都能跳转到指定的方位,而LDR PC,=???将向PC直接装载一个标号的值,请留意,标号在编译往后将被替换为一个与RO相对应的值,也便是说,这样的指令不管在哪里履行,都只会跳转到一个指定的方位.下面举一个详细的比如来阐明两者的差异:
假定有如下程序:
RESET
B INIT 或许 LDR PC,=INIT

INIT

其间RESET为开端时的代码,也便是这条代码的偏移为0,设INIT的偏移量为offset.假如将这段程序依照RO=0x1000000编译, 那么B INIT可了解为ADD PC, PC, #offset,而LDR PC,=INIT可被了解为 MOV PC,#(RO+offset) .明显当体系复位时,程序从0开端运转,而0地址有FLASH的副本,履行B INIT将把PC指向坐落0地址处的镜像代码方位,也即INIT;假如履行LDR PC,=INIT将会将PC直接指向坐落FLASH中的原始代码.因而以上两者都能正确运转.下面将RO设置为0x200000,编译后生成代码,仍是得烧写到FLASH中,也便是仍是0x100000,体系复位后从0地址履行,仍是FLASH的副本,此刻履行B INIT,将跳到副本中的INIT方位履行,此处有对应的代码;可是假如履行LDR PC,=INIT,将向PC加载0x200000+offset,这将使得PC跳到RAM中,而此刻因为代码没有仿制,RAM中的指定方位并没有代码,程序无法运转.

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/yingyong/iot/258039.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部