ARM的启动过程

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

ARM芯片的启动程序的分析和总结(2009-02-0414:35:26)转载标签:杂谈分类:ARM1、综述:目前大多基于ARM芯片的系统都是一个比较复杂的片上系统,多数硬件模块都是可配置的,可以通过软件来设置其需要的工作状态。因此在运行用户的应用程序之前,需要由专门的一段代码来完成对系统的初始化。这一段代码就称为启动程序。由于这类代码直接面对处理器内核和硬件控制器进行编程,一般都是用汇编语言。在ARM系统上电复位后,需要设置中断向量表、初始化各模式堆栈、设置系统时钟频率等,需要用ARM的汇编语言编写启动代码,由启动代码完成系统初始化以及跳转到用户C程序。在ARM设计开发中,启动代码的编写是一个极重要的过程。然而启动代码随具体的目标系统和开发系统有所区别,但通常包含以下部分:·向量表定义·地址重映射及中断向量表的转移·堆栈初始化·设置系统时钟频率·中断寄存器的初始化·进入C应用程序下面就结合PHILIPS的LPC2119的启动代码来分析与说明ARM7处理器的启动代码的编写。1.1向量表定义ARM芯片上电或复位后,系统进入管理模式、ARM状态、PC(R15寄存器)指向0x00000000地址处。中断向量表为每一个中断设置1个字的存储空间,存放一条跳转指令,通过这条指令使PC指针指向相应的中断服务程序入口,继而执行相应的中断处理程序。LPC2119的中断向量表和其它基于ARM核的芯片中断向量表较类似,只要注意LPC2119要使向量表所有数据32位累加和为零(0x00000000-0x0000001C的8个字的机器码累加),才能使用户的程序脱机运行。LPC2119的中断向量表如图1所示。1.2地址重映射及中断向量表的转移ARM7处理器在复位后从地址0读取第一条指令并执行,因此系统上电后地址0必须是非易失的ROM/FLASH,这样才能保证处理器有正确可用的指令。为了加快对中断的处理以及实现在不同操作系统模式下对中断的处理,这就需要重新映射中断向量表、Bootblock和SRAM空间的一小部分。ARM具有非常灵活的存储器地址分配特性。ARM处理器的地址重映射机制有两种情况:①由专门的寄存器完成重映射(Remap),只需对相应的Remap寄存器相应位设置即可。②没有专门的Remap控制寄存器需要重新改写用于控制存储器起始地址的块(Bank)寄存器来实现Remap。在LPC2119上的重映射,可以通过存储器映射控制器来实现。实现REMAP操作的程序实现如下:MOVR8,#0x40000000;/设置新向量表起始地址/LDRR9,=Interrupt_Vector_Table;/读原向量表源地址/LDMIAR9!,(R0-R7);/复制中断向量表及中断处理程序的入口地址到RAM中(64字节)/STMIAR8!,(R0-R7)LDMIAR9!,(R0-R7)STMIAR8!,(R0-R7)LDRR8,=MEMMAP;/REMMAP操作/MOVR9,#0x02STRR9,[R8]1.3堆栈初始化启动代码中各模式堆栈空间的设置是为中断处理和程序跳转时服务的。当系统响应中断或程序跳转时,需要将当前处理器的状态和部分重要参数保存在一段存储空间中,所以对每个模式都要进行堆栈初始化工作,给每个模式的SP定义一个堆栈基地址和堆栈的容量。堆栈的初始化有两种方法:第一种方法是结合ADS开发套件中的分散加载文件来定义堆栈。第二种方法是最简单也是最常用的一种就是直接进入对应的处理器模式,为SP寄存器指定相应的值。下面给出了用第二种方法初始化管理模式和中断模式堆栈的程序:MSRCPSR_c,#0xD3;/切换到管理模式,并初始化管理模式的堆栈/LDRSP,Stack_SvcMSRCPSR_c,#0xD2;/切换到IRQ模式,并初始化IRQ模式的堆栈/LDRSP,Stack_Irq…1.4系统部分时钟初始化时钟是芯片各部分正常工作的基础,应该在进入main()函数前设置。部分ARM7片子内部集成有PLL(锁相环)电路,用户可以用低频率的晶振通过PLL电路获得一个较高频率的时钟。LPC2119内部的PLL电路接受的输入时钟频率范围为10~25MHz,输入频率通过一个电流控制振荡器(CCO)倍增到范围10~60MHz。同时为了使高速的ARM处理器与低速的外设正常通讯和降低功耗(降低外设运行速度使功耗降低),LPC2119又集成了一个额外的分频器。PLL的激活是由PLLCON寄存器控制。PLL倍频器和分频器的值由PLLCFG寄存器控制。对PLLCON或PLLCFG寄存器的更改必须遵循严格的顺序,否则所作更改是无法生效的(在连续的VPB周期内向PLLFEED寄存器写入0xAA、0x55,在此期间中断必须是被禁止的。)1.5中断初始化ARM7的向量中断控制器(VectoredInterruptController)可以将中断编程为3类:FIQ、向量IRQ、非向量IRQ。FIQ中断请求的优先级最高,其次是IRQ中断请求,非向量IRQ的优先级最低。VIC具有32个中断请求输入,但在LPC2219中只占用了17个中断输入。对于这17个中断源的IRQ/FIQ选择,由VICIntSelect寄存器控制,当对应位设置位1时,则此中断为FIQ中断,否则为IRQ中断。若再将IRQ中断设置到向量控制寄存器(VICVectCntIn)中,则此中断为向量IRQ中断,否则为非向量IRQ中断。FIQ中断是专门用来处理那些需要及时响应的特殊事件,尽可能地只给FIQ分配一个中断源。1.6进入C应用程序至此,系统各部分的初始化基本完成,可以直接从启动代码转入到应用程序的main()函数入口。从启动代码转入到应用程序的实例代码如下:IMPORTmainLDRR0,=mainBXR02、总结一个优秀的启动代码将给应用程序的开发提供一个良好的开发平台。本文中较详细的讨论了启动代码的编写及难点。其中在堆栈初始化过程中要特别的注意两点:①要尽量给堆栈分配快速和高带宽的存储器。②尽量避免过早将处理器切换到用户模式,一般在系统初始化的最后阶段才切换到用户模式(用户模式没有权限通过修改CPSR来进行模式切换)。嵌入式系统的迅猛发展,使启动代码的编写成为嵌入式系统开发人员应该具备的能力。本文有助于正在从事嵌入式ARM开发的读者理解启动代码的内涵与编写出适合自己的启动代码。启动文件分析(试验总结)(以下所有完全是我自己在今晚对arm启动代码的所有理解,可能有很大的问题,但目前为止,我还是能自圆其说,还是另自己信服的,如果高手看出什么低级错误,欢迎指出,共同学习!)玩arm底层编程也有一个星期,感觉机会成熟,晚上认真把周立功的启动底层代码认真看了一遍,感觉豁然开朗,呵呵,赶快把学到的写在这里,怕以后忘记。完全理解这些基础的代码是学习移至uc/os或者uclinux的第一步,所有arm的核,甚至可以说x86的架构都是很相似的。这里所说的启动文件是没有任何操作系统,没有任何软件的基础上,去实现arm的编程,让程序运行于arm之上。简单的说就是arm上电复位,首先执行的代码,相当与x86的BIOS。如果想透彻了解,下面知识是必备的:c语言,汇编基础,arm的架构(对于arm底层开发,以及中断处理,假中断避免,调度算法,实时性分析都有很重要的帮助),arm常用指令。这些东西分别可以从谭浩强、杜春雷的书上找到解决方法。最好还要知道一些可执行文件的知识(hex和bin,ads产生的axf文件的差别,用utla还是很容易看出ro,rw,zi上的区别,二进制文件头还是有些不同的)。因为有操作系统和计算机组成原理的知识,所以进入下面一段,直入主题:拿周立功lpc2100开发板带的启动文件说事,其全部引导相关文件如下:config.h****************************配置文件lpc2XXX.h**************************此款芯片的头文件target.h***************************目标头文件heap.s****************************堆配置stack.s***************************栈配置IRQ.s*****************************中断配置startup.s***************************启动文件配置(VIC等)mem_b.scf*************************分散和加载文件(mem_a.scf类似,以b开刀)下面分别分析每个文件:打开文件config.h,其中关于数据类型的定义不用多说,是为了完成数据类型与平台无关,另一个重要的配置是系统晶振频率,VOC,VPB的配置,这个根据手册要求配置(比如说CCO频率,必须为Fcclk的2、4、8、16倍,范围为156MHz~320MHz),并且一定要和实际硬件相一致!这个文件,重要的就这一点点接着是lpc2XXX.h,里面是本处理器控制寄存器的地址宏定义,(*((volatileunsignedchar*)0xE01FC140))第一个*表示把后面的数字强制转换成地址,前面的*表示把宏定义的名称标为指向这个地址的指针。Target.h,启动定义了一些“空”函数给用户填写,用于处理特殊情况heap.s堆配置,仅仅分配了一个空间stack.s栈配置,与heap.s类似,作为异常向量入口及异常向量与c语言代码的接口irp.s这个文件值得研究,我把代码贴在下面,我把我懂的地方都注释了:NoIntEQU0x80//实际存储的地方USR32ModeEQU0x10//定义arm各个模式SVC32ModeEQU0x13SYS32ModeEQU0x1fIRQ32ModeEQU0x12FIQ32ModeEQU0x11CODE32AREAIRQ,CODE,READONLYMACRO$IRQ_LabelHANDLER$IRQ_Exception_FunctionEXPORT$IRQ_Label;输出的标号IMPORT$IRQ_Exception_Function;引用的外部标号$IRQ_LabelSUBLR,LR,#4;计算返回地址STMFDSP!,{R0-R3,R12,LR};把寄存器压栈保存任务环境MRSR3,SPSR;把spsR保存到R3中STMFDSP,{R3,LR}^;保存SPSR和用户状态的SP,注意不能回写;如果回写的是用户的SP,所以后面要调整SP^表示在压栈同时,保存SPSRNOPSUBSP,SP,#4*2//此句不理解MSRCPSR_c,#(NoInt|SYS32Mode);切换到系统模式BL$IRQ_Exception_Function;调用c语言的中断处理程序(函数返回)MSRCPSR_c,#(NoInt|IRQ32Mode);切换回irq模式LDMFDSP,{R3,LR}^;恢复SPSR和用户状态的SP,注意不能回写;如果回写的是用户的SP,所以后面要调整SP,此处^功能相似(参考uc/osarm移至要点详解)MSRSPSR_cxsf,R3;装载之前的SPSRADDSP,SP,#4*2;此句不理解LDMFDSP!,{R0-R3,R12,PC}^;恢复所有的调用之前寄存器状态MENDstartup.s文件:首先是定义每个栈的大小,然后是定义了一个PINSEL2根据芯片的pdf个人理解是设置pin的调试功能。接着引入一系列外部声明的函数,然后是非常重要的中断向量表,是要放在逻辑0x0的地址(所有向量相加应该为0!!),然后是初始化各个堆栈,接着进入了复位中断函数,ResetInitBLInitStack;初始化堆栈BLTargetResetInit;目标板基本初始化B__main;跳转到c语言入口下面还有些加密函数等等,重要的是堆栈的地址定义,因为有:MSRCPSR_c,#0xd2LDRSP,StackIrq,这里会调用下面的地址定义,这里注意,使用的是ldr而不是B,因为ldr支持全范围的跳转,可以在flash内,

1 / 31
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功