如何编写ARM7的启动代码

合集下载

ARM启动代码

ARM启动代码

arm启动代码详细分析所谓启动代码,就是处理器在启动的时候执行的一段代码,主要任务是初始化处理器模式,设置堆栈,初始化变量等等.由于以上的操作均与处理器体系结构和系统配置密切相关,所以一般由汇编来编写.具体到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,也需要一条跳转指令.具体代码如下:RESETB SYSINIT ; ResetB UDFHANDLER ; UNDEFINEDB SWIHANDLER ; SWIB PABTHANDLER ; PREFETCH ABORTB DABTHANDLER ; DATA ABORTB . ; RESERVEDB VECTORED_IRQ_HANDLERB . ; ADD FIQ CODE HEREUDFHANDLERB .SWIHANDLERB .PABTHANDLERB .DABTHANDLERB .请注意,B指令经汇编后会替换为当前PC值加上一个修正值(+/-),所以这条指令是代码位置无关的,也就是不管这条指令是在0地址还是在0x100000执行,都能跳转到指定的位置,而LDR PC,=???将向PC直接装载一个标号的值,请注意,标号在编译过后将被替换为一个与RO相对应的值,也就是说,这样的指令无论在哪里执行,都只会跳转到一个指定的位置.下面举一个具体的例子来说明两者的区别:假定有如下程序:RESETB 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中的指定位置并没有代码,程序无法运行.二,处理器模式ARM的处理器可工作于多种模式,不同模式有不同的堆栈,以下设置各模式及其堆栈.预定义一些参数:MODUSR EQU 0x10MODSYS EQU 0x1FMODSVC EQU 0x13MODABT EQU 0x17MODUDF EQU 0x1BMODIRQ EQU 0x12MODFIQ EQU 0x11IRQBIT EQU 0x80FIQBIT EQU 0x40RAMEND EQU 0x00204000 ; S64 : 16KB RAMVECTSIZE EQU 0x100 ;UsrStkSz EQU 8 ; size of USR stackSysStkSz EQU 128 ; size of SYS stackSvcStkSz EQU 8 ; size of SVC stackUdfStkSz EQU 8 ; size of UDF stackAbtStkSz EQU 8 ; size of ABT stackIrqStkSz EQU 128 ; size of IRQ stackFiqStkSz EQU 16 ; size of FIQ stack修改这些值即可修改相应模式堆栈的尺寸.以下为各模式代码:SYSINIT;MRS R0,CPSRBIC R0,R0,#0x1FMOV R2,#RAMENDORR R1,R0,#(MODSVC :OR: IRQBIT :OR: FIQBIT) MSR cpsr_cxsf,R1 ; ENTER SVC MODEMOV sp,R2SUB R2,R2,#SvcStkSzORR R1,R0,#(MODFIQ :OR: IRQBIT :OR: FIQBIT)MSR CPSR_cxsf,R1 ; ENTER FIQ MODEMOV sp,R2SUB R2,R2,#FiqStkSzORR R1,R0,#(MODIRQ :OR: IRQBIT :OR: FIQBIT)MSR CPSR_cxsf,R1 ; ENTER IRQ MODEMOV sp,R2SUB R2,R2,#IrqStkSzORR R1,R0,#(MODUDF :OR: IRQBIT :OR: FIQBIT) MSR CPSR_cxsf,R1 ; ENTER UDF MODEMOV sp,R2SUB R2,R2,#UdfStkSzORR R1,R0,#(MODABT :OR: IRQBIT :OR: FIQBIT)MSR CPSR_cxsf,R1 ; ENTER ABT MODEMOV sp,R2SUB R2,R2,#AbtStkSz;ORR R1,R0,#(MODUSR :OR: IRQBIT :OR: FIQBIT) ;MSR CPSR_cxsf,R1 ; ENTER USR MODE;MOV sp,R2;SUB R2,R2,#UsrStkSzORR R1,R0,#(MODSYS :OR: IRQBIT :OR: FIQBIT)MSR CPSR_cxsf,R1 ; ENTER SYS MODEMOV sp,R2 ;三,初始化变量编译完成之后,连接器会生成三个基本的段,分别是RO,RW,ZI,并会在image中顺序摆放.显然,RW,ZI在运行开始时并不位于指定的RW位置,因此必须初始化LDR R0,=|Image$$RO$$Limit|LDR R1,=|Image$$RW$$Base|LDR R2,=|Image$$ZI$$Base|1CMP R1,R2LDRLO R3,[R0],#4STRLO R3,[R1],#4BLO %B1MOV R3,#0LDR R1,=|Image$$ZI$$Limit|2CMP R2,R1STRLO R3,[R2],#4BLO %B2四,复制异常向量由于代码于RAM运行时,有明显的速度优势,而且变量可以动态配置,因此可以通过re map将RAM映射到0,使得出现异常时ARM从RAM中取得向量.IMPORT |Image$$RO$$Base|IMPORT |Image$$RO$$Limit|IMPORT |Image$$RW$$Base|IMPORT |Image$$RW$$Limit|IMPORT |Image$$ZI$$Base|IMPORT |Image$$ZI$$Limit|COPY_VECT_TO_RAMLDR R0,=|Image$$RO$$Base|LDR R1,=SYSINITLDR R2,=0x200000 ; RAM STARTCMP R0,R1LDRLO R3,[R0],#4STRLO R3,[R2],#4BLO %B0这段程序将SYSINIT之前的代码,也就是异常处理函数,全部复制到RAM中, 这就意味着不能将RW设置为0x200000,这样会使得向量被冲掉.四,在RAM中运行如果有必要,且代码足够小,可以将代码置于RAM中运行,由于RAM中本身没有代码,就需要将代码复制到RAM中:COPY_BEGINLDR R0,=0x200000LDR R1,=RESET ; =|Image$$RO$$Base|CMP R1,R0 ;BLO COPY_END ;ADR R0,RESETADR R2,COPY_ENDSUB R0,R2,R0ADD R1,R1,R0LDR R3,=|Image$$RO$$Limit|3CMP R1,R3LDRLO R4,[R2],#4STRLO R4,[R1],#4BLO %B3LDR PC,=COPY_ENDCOPY_END程序首先取得RESET的连接地址,判断程序是否时是在RAM中运行,方法是与RAM起始地址比较,如果小于,那么就跳过代码复制.在复制代码的时候需要注意,在这段程序结束之前的代码没有必要复制,因为这些代码都已经执行过了,所以,先取得COPY_END,作为复制起始地址,然后计算其相对RESET的偏移,然后以RO的值加上这个偏移,就是复制目的地的起始地址,然后开始复制.五,开始主程序以上步骤完成,就可以跳转到main运行IMPORT MainLDR PC,=MainB .六,器件初始化主程序首先要进行器件的初始化,对S64而言,应该先初始化WDT,因为默认情况下,W DT是打开的,然后是各设备的时钟分配,最后应该remapiar下.s79的分析BSP目录中的是和硬件平台代码相关的函数和定义。

实验一 ARM汇编程序的编写以及启动代码的分析

实验一 ARM汇编程序的编写以及启动代码的分析

实验ARM汇编程序的编写以及启动代码的分析一、实验目的:练习ARM汇编程序的编写,对提供的程序的启动代码进行分析,了解S3C2410初始化过程, 初始化代码主要是包含在start.s中。

二、实验原理:启动程序要完成的任务包括:硬件初始化,系统存储系统的配置,复制二级中断向量表。

启动程序过程●系统硬件初始化系统上电或复位后,程序从位于地址0x0的Reset Exception Vector处开始执行,因此需要在这里放置Bootloader的第一条指令:b ResetHandler,跳转到标号为ResetHandler处进行第一阶段的硬件初始化,执行完,系统进行堆栈和存储器的初始化。

使用了外设,则需要设置相关的寄存器,确定其刷新频率、总线宽度等信息。

●代码段复制到RAM中运行需要把系统的代码复制到RAM中运行。

映像文件内部共有三种输出段:RO段、RW段和ZI段。

ARMLink同时还产生了这三种输出段的起始和终止定位信息:Image$$RO$$Base、Image$$RO$$Limit、Image$$RW$$Base、Image$RW$Limit、Image$ZI$Base和Image$$ZI$$Limit。

可以在程序中使用这些定位信息。

将ROM中的代码和数据搬移到RAM中。

●建立二级中断向量表在ARM系统中,中断向量表位于0X0开始的地址处,意味着无论运行什么样的上层软件,一旦发生中断,程序就得到Flash存储器中的中断向量表里去,降低系统的运行效率。

因此在RAM中建立自己的二级中断向量表,当中断发生后,程序直接从RAM中取中断向量进入中断子程序。

尤其是在中断频繁发生的系统里,这种方法可以大大提高系统的运行效率。

三、实验内容:1.运行一个简单的串口程序,单步执行初始化代码,观察寄存器变化。

2.分析系统上电后的初始化工作包括哪些内容。

3.分析中断的处理过程,包括中断向量表的建立、中断源的识别及中断IRQ 服务程序是如何进入的。

ARM7启动代码

ARM7启动代码

ARM7启动程序班级:电子0801班姓名:****学号:200846751:PRESERVE8:Reguire8和Preserve8C和汇编有8位对齐的要求,这两个伪指令可以满足此要求,存在REQUIRE8<——> PRESERVE8的对应关系,但不是说有一个REQUIRE8就要有一个PRESERVE8,如果是一个c文件和一个汇编文件的调用,也就涉及一个PRESERVE8或者是一个REQUIRE8.另外,REQUIRE8和PRESERVE8并不完成8 byte 对齐的操作,对齐由ALIGN完成。

将ADS的代码移植到KEIL MDK上需要做的修改:当用户拥有ADS遗留工程的所有源代码时,使用MDK重新编译链接全部代码是最好的解决方法,MDK 中的新版本编译工具会重新生成满足堆栈8BYTE对齐要求的目标文件,避免由于堆栈不对齐引起的链接错误.从ADS到KEIL很重要的一个修改的地方就是这里的8BYTE对齐,想要编译通过,在startup.s里面我们必须加入PRESERVE8指令,使得寄存器8BYTE对齐.代码:CODE32PRESERVE8 ;这个在KEIL里面是必须的,要求8BYTE对齐.在ADS的启动代码中就没有.AREA vectors,CODE,READONLY2:ARM的处理器可工作于多种模式,下面设置个模式的一些参数.Mode_USR EQU 0x10 用户模式Mode_FIQ EQU 0x11 快中断模式Mode_IRQ EQU 0x12 中断模式Mode_SVC EQU 0x13 管理模式Mode_ABT EQU 0x17 中止模式Mode_UND EQU 0x1B 未定义模式Mode_SYS EQU 0x1F 系统模式参数的由来:这里各个模式的参数是由寄存器CPSR的模式位设置M[4:0]得来的,比如这里的用户模式,CPSR的M[4:0]设置为10000就是0x10,同理其他.详见<<ARM嵌入式系统基础教程>>P47页,CPSR设置很关键!3:I_Bit EQU 0x80 ; when I bit is set, IRQ is disabledF_Bit EQU 0x40 ; when F bit is set, FIQ is disabled也和CPSR寄存器的设置有关,这里两位是禁止/开启快速中断和一般中断的设置.4:各模式下定义的堆栈地址.UND_Stack_Size EQU 0x00000000SVC_Stack_Size EQU 0x00000100ABT_Stack_Size EQU 0x00000000FIQ_Stack_Size EQU 0x00000000IRQ_Stack_Size EQU 0x00000100USR_Stack_Size EQU 0x00000200设置堆栈大小Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size +FIQ_Stack_Size + IRQ_Stack_Size + USR_Stack_Size)AREA STACK, NOINIT, READWRITE, ALIGN=3Stack_Mem SPACE Stack_SizeStack_Top EQU Stack_Mem + Stack_Size堆栈大小的设置,各公司写的启动代码有所不同,但是不影响大局,可以借鉴一些你认为比较简单的启动代码,然后写自己的堆栈地址和大小设置程序.5:堆的设置Heap_Size EQU 0x00000000AREA HEAP, NOINIT, READWRITE, ALIGN=3Heap_Mem SPACE Heap_SizeAREA Init,CODE,READONLY,ALIGN=3 //指定后面的指令为8位对齐(2的3次方)align n它的含义就是使得下面的代码按一定规则对齐,.align n 指令的对齐值有两种方案,n 或2^n ,各种平台最初的汇编器一般都不是gas,采取方案1或2的都很多,gas的目标是取代原来的汇编器,必然要保持和原来汇编器的兼容,因此在gas中如何解释.align指令会显得有些混乱,原因在于保持兼容。

【ZLG微信文档精选】编写自己的ARM启动代码

【ZLG微信文档精选】编写自己的ARM启动代码
编写自己的 ARM 启动代码
Technical Note
TN01010101
V0.00
Date:2008/01/ຫໍສະໝຸດ 1ZLG 精选微信文章分享
类别 关键词
内容 ARM、启动代码 大家在使用 ARM 的 MCU 做产品开发时都见到过启动代码,它是什么鬼?如何


编写自己的启动代码?在成为嵌入式代码高手的路上, 看过此文你便可以将启动 代码斩于马下
程序清单 1 extern void __main( void ); void *const __vector_table[] __attribute__( ( section ( "Vector" ) ) ) = 使用 Keil/ARMCC 编译器
ZLG 精选微信文章分享
2
© 2012 Guangzhou ZLG MCU Technology Co., Ltd.
推送目的:干货分享 是否原创:是 关键字:ARM、启动代码 正文:
随着 ARM Cortex-M 系列 MCU 的普及,大家越来越多的开始接触 ARM,越来越多的 人开始拜入我 ARM 神教,我大 ARM 一统江湖之日不远啦~。 欲成为我大 ARM 教众,必得先学我大 ARM 武功,流水灯啦、矩阵键盘啦,都是我派 入门功夫,既然踏入江湖谁不想学点《九阴真经》 、 《易筋经》 、 《独孤九剑》这样的神功,有 神功护体,行走江湖才拉风嘛! 今天小编我就传授点神功法门,跟大家一起研究点上层武学。入门功夫往往学招式,神 功往往究其根本,在 ARM 里面也就是底层,底层的入口就在启动代码。欲学神功,必先搞 定启动代码, 就是大家在工程里面经常见到的 startup_xxxx.s 的那个汇编语言文件 (其中 xxxx 是芯片型号,如 startup_lpc17xx.s,这就是 LPC17xx 系列 MCU 启动代码) ,这是什么鬼呢? 说白了启动代码的核心功能是搭建 C 语言运行环境,如果你是 ARM 汇编的高手,可以 无视启动代码,但如果你使用的是 C 语言开发 ARM,那么启动代码就是必备的,标准启动 代码需要完成以下几个功能: 主堆栈指针以及堆栈的初始化; C Library 初始化; 中断向量表的初始化; 分散加载; 跳转到应用程序入口(默认是 main()函数) 。

ARM启动流程总结

ARM启动流程总结

ARM启动流程总结一、ARM7TDMI-S处理器1、ARM7TDMI-S处理器概述ARM7TDMI-S处理器是ARM通用32位微处理器家族成员之一。

ARM结构是基于精简指令集计算机(RISC)原理而设计的。

该处理器使用了冯.诺依曼(V onNeumann)结构,指令和数据共用一条32位总线。

只有装载、存储和交换指令可以对存储器中的数据进行访问。

该处理器有两个指令集:●32位ARM指令集●16位Thumb指令集2、指令流水线流水线使用3个阶段,因此指令分3个阶段执行:取指、译码、执行3阶段流水线如下图所示:注:程序计数器(PC)指向被取指的指令,而不是指向正在执行的指令。

二、指定程序段变量段在内存中位置的方法1、两种定位变量到指定位置方法(1)、使用定义在头文件absacc.h中的__at宏如:int x __at (0x40003000); // variable at address 0x40003000 (2)、采用分散加载技术表面定义就是把不同的程序段或数据段加载到不同的ROM或RAM地址。

一般为mem_a.scf文件。

同时,需设定编译连接器的路径:Options for Target->Linker->Scatter File中指定分散加载文件的路径。

三、ARM异常1、异常向量及异常以及各异常状态下的处理器模式(1)、异常优先级由高到低依次为:复位,数据中止,FIQ ,IRQ,预取指中止,未定义指令,SWI (2)、在异常向量中填充的是ARM跳转指令如:LDR PC, ResetAddrResetAddr DCD ResetInitResetInit: (复位入口)…(3)、ARM内核处理异常流程A、进入异常1、在对应处理器模式下的LR中保存下一条指令。

2、将CPSR复制到适当的SPSR中。

3、根据表2-4种异常进入时的模式将CPSR模式强制设为某一值。

4、强制PC从相关的异常向量处对下一条指令取指。

ARM7启动流程详解

ARM7启动流程详解
{
设置GPIO(GPIOCON,GPIODIR,GPIODAT)
设置GPON(PDCUC)
设置PWM(PWMP,PWM0,PWM1)
设置HANDFREE
禁止UART0和UART1上用于IRDA的脉冲波形
配置时钟频率OPCLK:clockfrequencyforSCcore,DSPcore,
初始化定时器TIMER0和TIMER1
设置UART0波特率,流量控制等
等待UART配置300us
向PC发送BOOT_INIT
初始化RTK
Rtk00Go();
初始化task和启动task
进入内核任务调度和消息处理}结束
}
初始化系统控制寄存器SYSCON
如果WATCHDOG已到达,则初始化DMA单元DMAU
配置PIO
配置中断控制器单元ICU(LIR0,LIR1,LIR2,LIR3,ICR,IMR)
初始化开关逻辑OOL,重新装载WATCHDOG
}
调用函数init_Main,进LCD和MEMORY电压
ARM7启动流程详解
1.ARM从地址0x00000000开始执行指令,为ARM的6个运行模式设
置栈
2.设置4个CS片选值如果WATCHDOG没到,重新设置BAI,否则
跳过
3.初始化GPIO如果WATCHDOG没到,重新设置LCD(打开
LCD),否则跳过
4.调用硬件初始化函数HardwareInit()

启动代码的说明


2:快速强制
• 高级中断控制器提供的快速强制提供了任意普通中 断源在快速中断控制器改向特性。通(AIC_FFER) 禁用寄存器(AIC_FFDR)的写入来实现。对这些寄存 器写操作将更新控制每个内部或外部中断源特性的 快速强制状态寄存器(AIC_FFSR)。当快速强制使能, 可以检测边沿,但源无法触发一个普通中断且不能 被优先级处理程序处理。 • 保留给快速中断的源0 维持正常操作,成为一个快 速中断源。 • 不管是否快速中断源,快速中断向量寄存器中断源 应通过写中断清除命令寄存器(AIC_ICCR) 来清除。

一:AT91 ARM 概述
使用户在高性能和高代码密度之间进行平衡。 ARM7TDMI处理器为冯-诺依曼结构,具有三级 流水线,即指令获取、解码和执行三个阶段。 ARM7TDMI处理器的主要特点是: • ARM7TDMI基于ARMv4T结构 • 两个指令集 – ARM® 高性能32 位指令集 – Thumb® 高代码密度16位指令集 • 三级流水线结构
启动代码的说明
1.什么是启动代码
启动代码是芯片复位进入C语言的main()函 数前执行的一段初始化程序,主要是为芯 片运行提供基本的运行环境,如初始化存 储系统、寄存器、PLL(锁相环)和内存 重映射,处理异常等。
ARM公司只设计芯片核心,不直接生产芯 片。不同的公司生产的芯片有各自不同的 特色,使得每一种芯片的启动代码差别很 大,不易编写出统一的启动代码。 相应芯片的启动代码需要按照数据手册 上的寄存器和工作模式来写 。 下面以AT91SAM7为列,说明如何按照 收据手册编写启动代码 。
• 4. 先前的步骤已使跳转到相应的中断服务程序。 若不需要嵌套快速中断,则不用保存链接寄存器 (R14_fiq) 及SPSR_fiq。 • 5. 中断处理程序按要求执行。由于FIQ自身有专 用寄存器且用户R8 到R13为组,因此不需要保存 寄存器R8 到R13。其它寄存器, R0 到R7,使用 前必须保存并在结束后恢复(在下一步前)。注意, 若快速中断编程为电平敏感,此时必须清除中断 源以便释放中断源0。 • 6. 最后,链接寄存器R14_fiq在减4后恢复到PC中 (例如,使用指令SUB PC, LR, #4 )。这样将返回 中断执行前的状态,将SPSR 中值载入CPSR 中, 是否屏蔽快速中断由存于SPSR 中的状态决定。

linux arm架构重启指令

linux arm架构重启指令
Linux ARM架构重启指令。

在Linux操作系统中,ARM架构是一种常见的处理器架构,被
广泛应用于嵌入式系统和移动设备中。

在ARM架构的Linux系统中,重启指令是一项非常重要的功能,它可以帮助用户在需要时快速地
重启设备,以解决一些系统问题或者应用程序崩溃的情况。

在Linux中,用户可以使用不同的方法来执行重启指令,其中
最常用的是使用命令行工具。

在ARM架构的Linux系统中,可以使
用以下命令来执行重启操作:
sudo reboot.
在这个命令中,“sudo”表示以超级用户权限执行命令,“reboot”表示重启操作。

当用户输入这个命令并确认后,系统将
会开始执行重启操作,关闭所有正在运行的程序并重新启动系统。

除了使用命令行工具外,用户还可以通过图形界面来执行重启
操作。

在大多数ARM架构的Linux发行版中,用户可以通过单击菜
单中的“重启”选项来执行重启操作。

这种方法更加直观和用户友好,适合那些不太熟悉命令行操作的用户使用。

无论是使用命令行工具还是图形界面,重启操作都是非常简单
和常用的功能。

在日常使用中,用户可能会遇到一些系统问题或者
应用程序崩溃的情况,这时候执行重启操作往往可以解决这些问题,恢复系统的正常运行。

总的来说,重启指令在Linux ARM架构系统中是一项非常重要
的功能,它为用户提供了一种快速解决系统问题的方法。

无论是通
过命令行工具还是图形界面,用户都可以方便地执行重启操作,确
保系统的稳定和正常运行。

ARM 启动代码详解(Vectors.c、Init.s、Target.c、 Target.h)

ARM 启动代码详解(Vectors.c、Init.s、Target.c、Target.h)启动代码是芯片复位后进入C语言的main()函数前执行的一段代码,主要是为运行C语言程序提供基本运行环境,如初始化存储器系统等。

ARM公司只设计内核,不自己生产芯片,只是把内核授权给其它厂商,其它厂商购买了授权且加入自己的外设后生产出各具特色的芯片。

这样就促进了基于ARM处理器核的芯片多元化,但也使得每一种芯片的启动代码差别很大,不易编写出统一的启动代码。

ADS(针对ARM 处理器核的C语言编译器)的策略是不提供完整的启动代码,启动代码不足部分或者由厂商提供,或者自己编写。

启动代码划分为4个文件:Vectors.c、Init.s、Target.c、Target.h。

Vectors.c包含异常向量表、堆栈初始化及中断服务程序与C程序的接口。

Init.s包含统初始化代码,并跳转到ADS提供的初始化代码。

Target.c和Target.h包含目标板特殊的代码,包括异常处理程序和目标板初始化程序。

这样做的目的是为了尽量减少汇编代码,同时把不需要修改的代码独立出来以减少错误。

§4.2.1 Vectors.c文件的编写§4.2.1.1 中断向量表VectorsLDR PC, ResetAddrLDR PC, UndefinedAddrLDR PC, SWI_AddrLDR PC, PrefetchAddrLDR PC, DataAbortAddrDCD 0xb9205f80LDR PC, [PC, #-0xff0]LDR PC, FIQ_AddrResetAddr DCD ResetUndefinedAddr DCD UndefinedSWI_Addr DCD SoftwareInterruptPrefetchAddr DCD PrefetchAbortDataAbortAddr DCD DataAbortnouse DCD 0IRQ_Addr DCD IRQ_HandlerFIQ_Addr DCD FIQ_Handler异常是由内部或外部源产生的以引起处理器处理的一个事件。

ARM启动代码详细讲解

ARM 启动代码详解(Vectors.c、Init.s、Target.c、 Target.h)2010-05-15 16:03启动代码是芯片复位后进入C语言的main()函数前执行的一段代码,主要是为运行C语言程序提供基本运行环境,如初始化存储器系统等。

ARM公司只设计核,不自己生产芯片,只是把核授权给其它厂商,其它厂商购买了授权且加入自己的外设后生产出各具特色的芯片。

这样就促进了基于ARM处理器核的芯片多元化,但也使得每一种芯片的启动代码差别很大,不易编写出统一的启动代码。

ADS (针对ARM处理器核的C语言编译器)的策略是不提供完整的启动代码,启动代码不足部分或者由厂商提供,或者自己编写。

启动代码划分为4个文件:Vectors.c、Init.s、Target.c、 Target.h。

Vectors.c包含异常向量表、堆栈初始化及中断服务程序与C程序的接口。

Init.s包含统初始化代码,并跳转到ADS提供的初始化代码。

Target.c和 Target.h包含目标板特殊的代码,包括异常处理程序和目标板初始化程序。

这样做的目的是为了尽量减少汇编代码,同时把不需要修改的代码独立出来以减少错误。

§4.2.1 Vectors.c文件的编写§4.2.1.1 中断向量表VectorsLDR PC, ResetAddrLDR PC, UndefinedAddrLDR PC, SWI_AddrLDR PC, PrefetchAddrLDR PC, DataAbortAddrDCD 0xb9205f80LDR PC, [PC, #-0xff0]LDR PC, FIQ_AddrResetAddr DCD ResetUndefinedAddr DCD UndefinedSWI_Addr DCD SoftwareInterruptPrefetchAddr DCD PrefetchAbortDataAbortAddr DCD DataAbortnouse DCD 0IRQ_Addr DCD IRQ_HandlerFIQ_Addr DCD FIQ_Handler异常是由部或外部源产生的以引起处理器处理的一个事件。

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

如何编写ARM7的启动代码(LPC2119为例)
随着生活水平的提高和IT技术的进步,8位处理器的处理能力已经不能满足嵌入式系统的需要了;而16位处理器在性能和成本上都没有很大的突破。

并且在8位机的开发中,大多使用汇编语言来编写用户程序。

这使得程序的可维护性、易移植性等都受到了极大的挑战。

正是基于此,ARM 公司适时的推出了一系列的32位嵌入式微控制器。

目前广泛使用的是ARM7和ARM9系列,ARM7TDMI内核的ARM7处理器广泛应用于工业控制、仪器仪表、汽车电子、通讯、消费电子等嵌入式设备。

本文主要以philips 公司ARM7TDMI核的LPC2119为例来分析如何编写ARM7的启动代码。

1、启动代码
在嵌入式系统软件的开发中,应用程序通常是在嵌入式操作系统的开发平台上采用C语言编写的。

然而,在ARM系统上电复位后,需要设置中断向量表、初始化各模式堆栈、设置系统时钟频率等,而这些过程都是针对
ARM内部寄存器结构的操作,用C语言编程是很难实现的。

因此在转到应用程序的c/c++编写之前,需要用ARM的汇编语言编写启动代码,由启动代码完成系统初始化以及跳转到用户C程序。

在ARM设计开发中,启动代码的编写是一个极重要的过程。

然而启动代码随具体的目标系统和开发系统有所区别,但通常包含以下部分:
·向量表定义
·地址重映射及中断向量表的转移
·堆栈初始化
·设置系统时钟频率
·中断寄存器的初始化
·进入C应用程序
下面就结合PHILIPS的LPC2119的启动代码来分析与说明ARM7处理器的启动代码的编写。

1.1向量表定义
ARM芯片上电或复位后,系统进入管理模式、ARM状态、PC(R15)指向0x00000000地址处。

中断向量表为每一个中断设置1个字的存储空间,存放一条跳转指令,通过这条指令使PC指针指向相应的中断服务程序入口,继而执行相应的中断处理程序。

LPC2219的中断向量表和其它基于ARM核的芯片中断向量表较类似,只要注意LPC2219要使向量表所有数据32位累加和为零(0x00000000-0x0000001C的8个字的机器码累加), 才能使用户的程序脱机运行。

1.2 地址重映射及中断向量表的转移
ARM7处理器在复位后从地址0读取第一条指令并执行,因此系统上电后地址0必须是非易失的ROM/FLASH,这样才能保证处理器有正确可用的指令。

为了加快对中断的处理以及实现在不同操作系统模式下对中断的处
理,这就需要重新映射中断向量表、BootbLOCk和SRAM空间的一小部分。

ARM具有非常灵活的存储器地址分配特性。

ARM处理器的地址重映射机制有两种情况:
①由专门的寄存器完成重映射(Remap),只需对相应的Remap寄存器相应位设置即可。

②没有专门的Remap控制寄存器需要重新改写用于控制存储器起始地址的块(Bank)寄存器来实现Remap。

在LPC2119上的重映射,可以通过存储器映射控制器来实现。

实现REMAP操作的程序实现如下:
MOV R8,#0x40000000; /设置新向量表起始地址/
LDR R9,=Interrupt_Vector_Table; /读原向量表源地址/
LDMIA R9!,(R0-R7); /复制中断向量表及中断处理程序的入口地址到RAM中(64字节)/
STMIA R8!,(R0-R7)
LDMIA R9!,(R0-R7)
STMIA R8!,(R0-R7)
LDR R8,=MEMMAP ; /REMMAP操作/
MOV R9,#0x02
STR R9, [R8]
1.3 堆栈初始化
启动代码中各模式堆栈空间的设置是为中断处理和程序跳转时服务的。

当系统响应中断或程序跳转时,需要将当前处理器的状态和部分重要参数保存在一段存储空间中,所以对每个模式都要进行堆栈初始化工作,给每个模式的SP定义一个堆栈基地址和堆栈的容量。

堆栈的初始化有两种方法:第一种方法是结合ADS开发套件中的分散加载文件来定义堆栈。

第二种方
法是最简单也是最常用的一种就是直接进入对应的处理器模式,为SP寄存器指定相应的值。

下面给出了用第二种方法初始化管理模式和中断模式堆栈的程序:
MSR CPSR_c, #0xD3 ; /切换到管理模式,并初始化管理模式的堆栈/ LDR SP, Stack_Svc
MSR CPSR_c, #0xD2 ; /切换到IRQ模式,并初始化IRQ模式的堆栈/ LDR SP, 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的向量中断控制器(Vectored Interrupt Controller)可以将中断编程为3类:FIQ、向量IRQ、非向量IRQ。

FIQ中断请求的优先级最高,其次是IRQ中断请求,非向量IRQ的优先级最低。

VIC具有32个中断请求输入,但在LPC2219中只占用了17个中断输入。

对于这17个中断源的IRQ/FIQ选择,由VICIntSelect寄存器控制,当对应位设置位1时,则此
中断为FIQ中断,否则为IRQ中断。

若再将IRQ中断设置到向量控制寄存器(VICVectCn TI n)中,则此中断为向量IRQ中断,否则为非向量IRQ中断。

FIQ中断是专门用来处理那些需要及时响应的特殊事件,尽可能地只给FIQ 分配一个中断源。

1.6 进入C应用程序
至此,系统各部分的初始化基本完成,可以直接从启动代码转入到应用程序的main()函数入口。

从启动代码转入到应用程序的实例代码如下:IMPORT main
LDR R0,=main
BX R0
2、总结
一个优秀的启动代码将给应用程序的开发提供一个良好的开发平台。

本文中较详细的讨论了启动代码的编写及难点。

其中在堆栈初始化过程中要特别的注意两点:
①要尽量给堆栈分配快速和高带宽的存储器。

②尽量避免过早将处理器切换到用户模式,一般在系统初始化的最后阶段才切换到用户模式(用户模式没有权限通过修改CPSR来进行模式切换)。

相关文档
最新文档