




已阅读5页,还剩20页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
ARM体系结构与编程参考资料V1.01第8章 S3C2440系统启动1. 概述一般情况,嵌入式系统分为两部进行工作,一部份是采用汇编编写的,它的作用是在应用程序运行之前对系统硬件及软件运行环境进行必要的初始化,并在最后使程序跳转到应用程序。汇编代码虽然效率高,但代码可读性和可维护性比较差,因此,这一部份代码要尽量精减,这个阶段主要是给C/C+等高级语言程序准备执行环境;另一部份是采用C/C+编写的应用程序,采用C/C+编写的代码可读性和可维护性更好,因此,是系统大部份是采用它来完成。这两部份虽然是一个连续性整体,但为了更好的理解系统的启动过程,我们将它们分离成两部份,并命名为“ 启动代码”和“应用程序”以便于分析。启动代码是系统上电或复位以后运行的第一段代码,它直接面对ARM处理器内核及硬件控制器进行编程,所执行的操作与具体的目标系统紧密相关。2. 系统启动描述因为启动代码与目标系统紧密相连,所以在分析启动代码之前,先了解一下S3C2440的启动方式。S3C2440 支持两种方式的启动:Nor Flash 启动和 Nand Flash 启动。Nor Flash 和 Nand Flash 都是非易失性存储器,Nor Flash 的特点是芯片内执行,程序可以直接在其中运行,而不必将程序读取到 RAM 中运行 。Nor Flash 虽然具有这个优点,但是它的性价比远低于 Nand Flash,因而很多系统采用 Nand Flash 启动。Nand Flash 的特点是采用非线性存储模式,程序无法在其中运行,它只能作为程序或数据的存储载体,存储在其中的程序只能先拷贝到 RAM 中才能运行。 S3C2440的引脚OM1:0等于“01”或“10”时,即为Nor Flash 启动,与 nGCS0 相连的 Nor Flash 就被映射到 nGCS0 片选的空间,其地址被映射为0x00000000;当系统上电或复位时,程序会从 0 地址处开始执行,因此我们编写的启动代码要确保存储在 0 地址处。当启动方式为 Nor Flash 启动时,没有额外需要考虑的问题,因为这种情况下程序在系统启动前就存储在 Nor Flash 中,我们只要保证将启动代码保存在 Nor Flash 开始的位置即可,系统上电或复位时,0 地址处的启动代码就会被执行。 S3C2440的引脚OM1:0等于“00”时,即为Nand Flash 启动,S3C2440 芯片内部自带的一块容量为 4K 的被称为“Steppingstone”的 BootSRAM 被映射到 nGCS0 片选的空间,其地址被映射为 0x00000000。在启动方式为 Nand Flash 启动的情况下,系统启动前所有的程序存储在 Nand Flash 中,系统的启动过程稍微有点复杂:系统上电或复位时,0 地址处为 S3C2440 内部自带的 BootSRAM,启动前里面没有任何存储内容,启动后 S3C2440 先通过硬件机制将 Nand Flash 前 4K 的内容拷贝至其中,然后再运行里面的程序(从 0 地址处)。这种情况下我们需要保证将启动代码保存在 Nand Flash 开始的位置,并且启动代码的大小要小于 4K。1) 如果系统的所有程序在编译链接后的大小小于 4K,那在系统的启动代码中无需考虑将程序从 Nand Flash 搬运到 SDRAM 这个问题,因为所有的程序在启动时即全部由 Nand Flash 拷贝至BootSRAM,程序在 BootSRAM 中运行即可;2) 如果系统的所有程序在编译连接后的大小大于 4K,那在系统的启动代码中需要包含一段将系统的全部程序从 Nand Flash 搬运到 SDRAM 的代码,因为系统启动时只将 Nand Flash 的前 4K 拷贝到了 BootSRAM 中,还有部分程序保存在 Nand Flash 中, Nand Flash 中是无法运行程序的,需要将所有程序拷贝至 SDRAM 并在其中运行,所以在系统的启动代码中要包含这段有关程序拷贝的代码,并在所有程序拷贝完成后使程序跳转到 SDRAM 中运行。也就是说在启动方式为 NandFlash 启动的情况下,因为 Nand Flash 的特性,程序需要涉及到两次的搬移,一次是从 Nand Flash 搬移到BootSRAM,搬运的程序量大小是 4K,目的是使系统能够启动;第二次搬运是从 Nand Flash 搬运到系统的SDRAM,如果系统的所有程序量小于 4K,这一步可以省略,搬运的程序量大小是系统的所有程序,目的是使程序在 SDRAM 中运行。第一次搬运是 S3C2440 通过硬件机制自动实现的,我们无需干预,第二次则需要我们程序员来实现。开发板带有两种 FLASH:2M 的 Nor Flash和256M 的 Nand Flash。启动方式可通过拨键开关S2 来选择。此处讲解的内容是基于 Nor FLASH 启动的。启动代码主要是在主程序运行之前初始化系统硬件及软件的运行环境,它的主要功能包括以下几个方面: 建立异常向量表 硬件环境初始化 软件环境初始化 跳转到应用程序2.1. 建立异常向量表异常向量表一般位于启动代码的开始部分,它是用户程序与启动代码之间以及启动代码的各部分之间联系的纽带。它由一个一个的跳转函数组成,它就像一个普通的散转函数,只不过散转的过程中有硬件机制参与,当系统发生异常时,ARM 处理器会通过硬件机制强制将 PC 指针指向异常向量表中对应的异常跳转函数存储的地址,然后程序会跳转到相应的异常中断服务程序去执行。下面我们来逐步了解一下异常向量表。ARM 有 7 种异常,它们分别是: 复位异常,当开发板上电或复位时进入; 未定义指令异常,当遇到无法识别的指令时进入; 软中断异常,当发生软中断时进入; 预取中止异常,发生指令预取错误时进入; 数据中止异常,对数据访问不能完成时进入; IRQ 异常,当发生 IRQ 中断时进入; FIQ 异常,当发生 FIQ 中断时进入;除了这 7 种异常之外,异常向量表中还有一个保留位置,所以建立异常向量表需要开辟一块大小为 84 字节的空间,每个异常占据一个字(4 个字节)的空间,这一个字的空间包含的是一个跳转指令,通过这条指令使 PC 指向相应异常处理函数的入口,具体的异常处理函数在别处实现。异常向量表中指令、存储地址等对照表如下表所示:地址指令异常名称进入时处理器模式0x00B HandlerReset复位异常管理模式0x04B HandlerUndef未定义指令异常未定义模式0x08B HandlerSWI软中断异常管理模式0x0cB HandlerPabort指令预取异常中止模式0x10B HandlerDabort数据中止异常中止模式0x14B .保留0x18B HandlerIRQIRQ 中断异常中断模式0x1cB HandlerFIQFIQ 中断异常快中断模式ARM 要求异常向量表必须存储在 0 地址处,这样当开发板上电或复位时,PC 会指向 0 地 址 处 ,进而跳转到复位异常处理函数函数 HandlerReset,这个函数负责完成系统的初始化工作,即硬件环境初始化、软件环境初始化、跳转至主函数;发生其他异常时 ARM 通过硬件机制将 PC 指向异常向量表对应的位置,进而跳转至相应的异常处理函数。2.2. 硬件环境初始化硬件环境初始化是为建立一套基础的应用程序执行环境准备硬件环境,这个初始化过程包括:关闭看门狗,屏蔽FIQ和IRQ中断,初始化系统时钟(PLL),初始化存储系统以及一些必要的其他硬件初始化操作,当然,并不是所有硬件的初始化都要在这里完成,在系统启动过程中一般只初始化一些和应用程序执行环境的建立有密切关系的硬件,其他的硬件可以在应用程序启动后根据需要进行初始化,这样有利于将用汇编写的启动代码精减到最小,而更多的采用C/C+等高级语言来编写代码,增加代码的可读性和可维护性。 关闭看门狗在系统启动过程中,没有启动喂狗的任务,不关闭看门狗有可能会导致在系统启动过程中由于看门狗超时导致系统被复位,因此,需要先关闭看门狗,待应用程序执行环境建立好后,再根据需要启动开门狗。 屏蔽FIQ和IRQ中断在系统过程中,应用程序执行环境初始化完成前,中断的处理程序的环境也还没有建立好,这个时候如果发生中断将会导致不可预料的后果,因此,需要先将中断屏蔽掉,待应用程序执行环境建立好后,再根据需要开启中断 初始化系统时钟(PLL)如果说处理器是整个系统的心脏,那么晶振就是整时系统的心脏,它负责向输送血液(时钟频率)给各个硬件部件,以驱动它们进行工作,系统中的每个硬件的运行都跟时钟频率有密切关系,只有先确定了时钟频率才能够对每个硬件进行正确的初始化。 初始化存储系统硬件是驱干,软件是灵魂,存储系统是灵魂的依附,为了能够让应用程序正确的运行起来,系统启动后中,需要从ROM中加载程序,并在RAM中运行它,因此,只有对存储系统进行正确的初始化才能够让应用程序在系统中正确的执行。2.3. 软件环境初始化硬件环境准备完成后,需要对应用程序的软件环境进行初始化工作,这些工作包括系统堆栈初始化,RO/RW/ZI初始化,必要的时候还要进行MMU的初始化工作,在这些初始化完成后,整个系统的应用程序执行环境初始化的工作就准备就绪,可以调用采用C/C+编写的应用程序的主函数,执行应用程序。 系统堆栈初始化由于考虑到成本及处理器体积的大小,每一款处理器的寄存器都是相当有限的,但在系统运行过程中却有可能大量的临时数据需要被保存,这不可能全部存到寄存器中,而RAM容量大,成本也比较低,我们需要在RAM中开辟一块空间,专门用于保存这些临数据。每一种处理器模式都有其独享的一个堆栈空间。 RO/RW/ZI初始化在程序运行中,我们会涉及到三种类型的数据,RO是代码和常量数据,这是只读的数据,RW具有初始化的变量数量,这些数据变量会被读取并被必写,ZI只是定义了变量,但并未对其进行初始化的,我们系统默认将其初始化为0x00,这此数据在系统运行过程中需要被搬移到相应的存储空间才能保障系统正常运行。 MMU地址重映射MMU的主要作用是实现虚拟地址到实际物理地址的映射,即对处理器的地址进行重新映射,它的目的有两个:一是用于将代码从ROM中移到速度较高的RAM中运行时可以将0地址进行重新映射以保证软中断异常的正常执行。二是用于现代高级操作系统对进程地址空间的隔离保护,对每个进程采用不同的虚拟地址映射表,每个进程同一个虚拟地址指向不同的物理地址,减少进程间内存互相破坏的可能性。关于MMU的详细使用在后续会采用专门的章节进行介绍。2.4. 跳转到应用程序在所有的准备工作都做好以后,启动代码的最后一步就是跳转到主函数,主函数我们在其他文件中用 C 语言实现的。从启动代码跳转到主程序有两种方法:1) 使用如下指令跳转到自己编写的主函数B Main使用此指令的时候要注意:Main 函数是我们自己编写的,为避免和编译器提供的主函数_main 发生混淆,最好将其写为 Main,而不要写成 main。采用这种方法来跳转到主程序时,要自己编写代码来实现应用程序执行环境的初始化。2) 使用如下指令跳转到编译器提供的主函数B _main_main 是编译器提供的一个函数,它有两个作用,一个作用就是调用_Scatterload 函数,将RW 和 RO 段从装载地址复制到运行地址,并完成 ZI 段的清零工作,这一功能就是上一点讲到的应用程序执行环境初始化,调用_main 可以由编译器隐式的完成;另一个功能是库函数调用的初始化,它是通过调用_rt_entry 函数来完成的,库函数初始化完成以后就会自动跳转到 main 函数执行。但是使用_main 时,用户需要重新来实现_user_ininial_stackheap 函数,这个函数的作用是初始化库函数的堆栈。由于已经自己编写代码实现了软件环境的初始化,所以不要使用第二种方式。3. 系统启动流程3.1. 关闭看门狗看门狗定时器控制寄存器WTCON的WTCON.5的位是其使能位,只要将其置为0就可以关闭看门狗,由于看门狗关闭后,它的配置参数也没有任用处,因此可以直接将整个WTCON设置为0进行关闭。示例代码:LDR R0, =WTCON;加载看门狗定时器控制寄存器的地址到R0LDR R1, =0x00;加载看门狗定时器控制寄存器的配置值到R1STR R1, R0;给看门狗定时器赋值3.2. 屏蔽FIQ和IRQ中断在程序状态寄存器CPSR中,CPSR的I位和F位分别是IRQ和FIQ的中断禁止位,只要将这两个位置为1就可以禁止产生IRQ和FIQ中断.示例代码:;定义IRQ和FIQ的中断掩码常量DISABLE_IRQ_FIQ_MSK EQU 0x000000C0;将CPSR的I位和F位置0MRS R0,CPSR;读取CPSR的值到寄存器R0ORR R0,R0,#DISABLE_IRQ_FIQ_MSK;通过或方式将R0中对应的I位和F位置1MSR CPSR_c,R0;保存新的CPSR的值到CPSR中3.3. 配置系统时钟3.3.1. 时钟系统概述S3C2440的时钟控制逻辑既可以外接晶振,然后通过内部电路产生时钟源,也可以直接外接提供的时钟源,它们通过引脚的设置来选择。S3C2440的CPU核心工作电压为1.3V时,主频可以达到400MHz,为了满足板间布线的要求,S3C2440外接的晶振频率通常很低,一般为12MHz或16.9344MHz,需要通过时钟控制逻辑的PLL(锁相环)进行多次位频以提高系统时钟,12MHz的晶振用得最多,因此,我们这里的讲解也以12MHz为例。S3C2440有两个PLL:MPLL和UPLL,MPLL专用于设置FCLK,HCLK,PCLK 为处理器核心和各种总线上的设备提供时钟,稳定的最高频率可以达到400MHz,而UPLL专用于USB设备,目前USB的时钟频率固定为48MHz。FCLK,HCLK和PCLK时钟的作用分别如下: FCLK 等于MPLL,它用于CPU核心,就是CPU的主频。 HCLK是通过对FCLK按比例分频后得到,它用于高速的AHB总线上的设备,比如CPU核、存储控制器、中断控制器、LCD控制器、DMA和USB主机模块等。 PCLK是通过对HCLK按比例分频后得到,它用于慢速的APB总线上的设备,比如Watchdog、IIS、I2C、PWM定时器、MMC接口、ADC、UART、GPIO、RTC和SPI等设备。系统刚上电时,PLL没有启动,FCLK等于外部输入时钟,成为Fin,如果要提高系统时钟,需要软件来启动PLL。下面来介绍PLL的设置过程:MPLL,UPLL的产生过程:外部晶振输入一个时钟频率给PLL模块,PLL模块通过预先设定的MPLL和UPLL的PDIV,MDIV,SDIV三个分频系数的作用下分别输出了MPLL和UPLL两个新的时钟源, 在PLL产生的过程中,我们需要给出三个系数,PDIV分频序数,MDIV分频系数,SDIIV分频系数,在S3C2440的处理器中,这三个分频系数分别通过MPLLCON和UPLLCON两个寄存器进行配置(具体寄存器的配置方式,我们在后续介绍)。这三个分频系数与PLL时钟的关系如下:PLL时钟与外部晶振时钟的关系如下MPLL = (2*m*Fin)/(p*2s)UPLL = (m*Fin)/(p*2s)其中m=MDIV+8, p=PDIV+2, s=SDIV, Fin=外部晶振频率FCLK,HCLK和PCLK的产生过程:FCLK其实就是系统的主时钟MPLL,HCLK是由FCLK经过一定比例分频得出的,它的分频系序由HDIV系数来控制,PCLK是由HCLK经过一定比例分频得出的,它的分频系序由PDIV系数来控制。HDIV和PDIV是由CLKDIV寄存器配置的(具体寄存器的配置方式,我们在后续介绍)。摄像头的时钟分频器HCLK3_HALF/HCLK4_HALF也会影响到HCLK和PCLK的分频比例,具体可以参考S3C2440的数据手册。FCLK,HCLK,PCLK,HDIV,PDIV的配比关系如下图:HDIVNPDIVNHCLK3_HALF/HCLK4_HALFFCLKHCLKPCLK分频比00-FLCKFLCKFLCK1:1:101-FLCKFLCKFLCK/21:1:210-FLCKFLCK/2FLCK/21:2:211-FLCKFLCK/2FLCK/41:2:4300/0FLCKFLCK/3FLCK/31:3:3310/0FLCKFLCK/3FLCK/61:3:6301/0FLCKFLCK/6FLCK/61:6:6311/0FLCKFLCK/6FLCK/121:6:12200/0FLCKFLCK/4FLCK/41:4:4210/0FLCKFLCK/4FLCK/81:4:8200/1FLCKFLCK/8FLCK/81:8:8210/1FLCKFLCK/8FLCK/161:8:16UCLK产生的过程:UPLL产生后,经过一次的DIVN_UPLL的分频,会产生UCLK,DIVN_UPLL的具体参数配置参考CLKDIVN寄存器。PLL各种时钟产生示意图如下:注意:如果HDIVN非0,CPU的总线模式应该从快速总线模式变为异步总线模式,通过下面指令:mrc p15, 0, r0, c1, c0, 0orr r0, r0, 0xC0000000mcr p15, 0, r0, c1, c0, 0如果CPU的总线模式仍是快速总线模式,则CPU的工作频率将自动变为HCLK,而不是FCLK.这种方式可以用在降低CPU工作频率,却又不影响HCLK和PCLK的频率。上电后MPLL启动的过程: 上电几毫秒后,晶振(OSC)输出稳定,FCLK=Fin(晶振频率),nRESET信号恢复高电平后,CPU开始执行指令,这个过程完全由硬件自行控制,不需要软件干预。 系统程序启动后,我们可以启动MPLL,并根据需要对MPLL进行配置,刚设置完MPLL时, MPLL需要一定时间频率输出才能稳定,这段时间称之为Lock Time,在Lock Time期间,FCLK停止供应时钟,CPU停止工作。Lock Time长短由寄存器LOCKTIME设定。 Lock Time之后,MPLL输出稳定,FCLK恢复供应时钟,CPU正常工作在FCLK下,HCLK和PCLK也得到相应比例的稳定频率。上电后,MPLL的时序图如下:由上图我们可以知道,在MPLL和UPLL设置完成后,新的频率的输出需要一定的稳定周期,这个时间段需要让CPU处理暂停状态,这个时间段由寄存器LOCKTIME来设定(具体寄存器的配置方式,我们在后续介绍)。3.3.2. 时钟系统的相关寄存器1) LOCKTIME锁定时间计数寄存器寄存器地址读/写描述复位值LOCKTIME0x4C000000读写锁定时间计数寄存器0xFFFFFFFFLOCKTIME寄存器说明:LOCKTIME功能位描述复位值U_LTIME31:16UPLL 对于UCLK 的锁定时间计数值.( U_LTIME:300uS)0xFFFFM_LTIME15:0MPLL对于FCLK、HCLK、PCLK的锁定时间计数值( M_LTIME:300uS)0xFFFF2) PLLCON锁定时间计数寄存器寄存器地址读/写描述复位值MPLLCON0x4C000004读写MPLL配置寄存器0x00096030UPLLCON0x4C000008读写UPLL配置寄存器0x0004d030PLLCON寄存器说明:PLLCON功能位描述复位值MDIV19:12主分频器控制0x96/0x4dPDIV9:4预分频器控制0x03/0x03SDIV1:0后分频器控制0x0/0x0注:当你设置MPLL和UPLL值的时候,需要先设置UPLL再设置MPLL的值,并且,在UPLL设置完成后,需要延迟一定的时间后再设置MPLL,一般是延迟7个时钟周期。Pll时钟频率计算公式:Mpll = (2 * m * Fin)/(p * 2s)m = (MDIV + 8), p = (PDIV + 2), s = SDIVUPLL Control RegisterUpll = (m * Fin)/(p * 2s)m = (MDIV + 8), p = (PDIV + 2), s = SDIVPll配置的取值范围: Fout = 2 * m * Fin / (p*2s), Fvco = m * Fin / p,m=MDIV+8,p=PDIV+2,s=SDIV 600MHz = FVCO=1.2GHz 200MHz =FCLKOUT =600MHz 不能设置P和M值为零,因为P=000000, M=00000000 会引起PLL故障。 合适的P、M值范围是: 1 P 62, 1 M 248PLL值选择表:一般较难找到一个合适的PLL值,因此推荐参考以下PLL推荐值表:输入频率输出频率MDIVPDIVSDIV12.0000MHz48.00MHz(UPLL)56(0x38)2212.0000MHz96.00MHz(UPLL)56(0x38)2112.0000MHz271.50MHz173(0xad)2212.0000MHz304.00MHz68(0x44)1112.0000MHz405.00MHz127(0x7f)2112.0000MHz532.00MHz125(0x7d)1112.0000MHz47.98MHz(UPLL)60(0x3c)4216.9344MHz95.96MHz(UPLL)60(0x3c)4116.9344MHz266.72MHz118(0x76)2216.9344MHz296.35MHz97(0x61)1216.9344MHz399.65MHz110(0x6e)3116.9344MHz530.61MHz86(0x56)1116.9344MHz533.43MHz118(0x76)11注:48MHz和96MHz输出是用于UPLL。3) CLKDIVN时钟分频器控制寄存器寄存器地址读/写描述复位值CLKDIVN0x4C000014R/W时钟分频器控制寄存器0x00000000CLKDIVN寄存器说明:CLKDIVN功能位描述复位值DIVN_UPLL3UCLK 选择寄存器(UCLK必须对USB提供48MHz)0: UCLK = UPLL clock1: UCLK = UPLL clock / 2设置为0,当UPLL时钟被设置为48Mhz。设置为1,当UPLL 时钟被设置为96Mhz。0HDIVN2:100: HCLK = FCLK/1.01: HCLK = FCLK/2.10: HCLK = FCLK/4,当CAMDIVN9 = 0.HCLK = FCLK/8,当CAMDIVN9 = 1.11: HCLK = FCLK/3,当CAMDIVN8 = 0.HCLK = FCLK/6,当CAMDIVN8 = 1.00PDIVN00: PCLK 是和HCLK/1 相同的时钟。1: PCLK 是和HCLK/2 相同的时钟。03.3.3. 时钟系统的配置进行系统时钟配置时我们需要先设定一个系统要运行的时钟主频率,然后再根据公式计算出MPLL的MDIV,PDIV,SDIV的参数值,USB时钟频只能是48MHz,而且UPLL顶多只能进行一次1/2分频获取UCLK,因此,UPLL只能选择96 MHz或48 MHz,确定了MDIV,PDIV,SDIV后,再根据系统运行需要确定HCLK和PCLK的比分频比例。3.4. 初始化存储系统一般情况下,一个嵌入式系统会外接有一到两片的Flash(NorFlash/NandFlash),一到两片的SDRAM,典型的嵌入式系统是一片小容量(2-4M)的NorFlash用于存储系统程序和关键参数,另一片大容(16M-1G)NandFlash用存储运行业务数据,然后一片SDRAM作为程序的RAM空间。在系统运行初期需要对有外接存储器的存储控制器进行正确的参数配置。存储控制器由于涉及到外部组件,因此,其工作参数需要与外部组件相匹配,在进行参数配置时,需要先查看外部存储部件数据手册中的要求,然后做恰当的配置才能够使组件良好工作。关于外部存储系统的配置方式在存储控制一章中有详细的介绍,请参考该章节的内容。3.5. 初始化系统堆栈3.5.1. 系统堆栈概述堆栈严格来说应该叫做栈,它一般是用于存放函数的参数值,局部变量的值,处理器模式或着函数调用时保存现场环境等。栈操作方式:栈(Stack)是限定仅在一端进行插入或删除操作的线性表。因此,对栈来说,可以进行插入或删除操作的一端称为栈顶(top),相应地,另一端称为栈底(bottom)。不含元素的空表称为空栈。由于堆栈只允许在一端进行操作,因而按照后进先出(LIFO-Last In First Out)的原理运作。 从栈顶的定义来看,栈顶的位置是可变的。空栈时,栈顶和栈底重合;满栈时,栈顶离栈底最远。堆栈可分为两种类型:向上生长:向高地址方向生长,称为递增堆栈向下生长:向低地址方向生长,称为递减堆栈 堆栈指针指向最后压入的堆栈的有效数据项,称为满堆栈;堆栈指针指向下一个要放入的空位置,称为空堆栈。这样就有4中类型的堆栈表示递增和递减的满堆栈和空堆栈的各种组合。满递增:堆栈通过增大存储器的地址向上增长,堆栈指针指向内含有效数据项的最高地址。指令如LDMFA,STMFA等。空递增:堆栈通过增大存储器的地址向上增长,堆栈指针指向堆栈上的第一个空位置。指令如LDMEA,STMEA等。满递减:堆栈通过减小存储器的地址向下增长,堆栈指针指向内含有效数据项的最低地址。指令如LDMFD,STMFD等。空递减:堆栈通过减小存储器的地址向下增长,堆栈指针指向堆栈下的第一个空位置。指令如LDMED,STMED等。 为什么说“向上生长”和“向下生长”呢?那是以为,一般画堆栈示意图都是把低地址画在下面,高地址画在上面。如下图。3.5.2. 系统堆栈的配置ARM为堆栈提供了硬件支持,它使用一个专门的寄存器(堆栈指针)指向堆栈的栈顶。ARM的7种模式分别对应6个不同的堆栈指针物理寄存器,其中的一个是用户模式与系统模式共用,另外5个物理寄存器对应于其他5种不同的运行模式,因此,除了用户模式与系统共用之外,其他的5种模式下都有各自独立的堆栈空间,用户可以根据自己系统在每一种模式下对堆栈的实际使用量对其作相应的配置。堆栈是为中断或程序跳转服务的,当发生中断或程序跳转时,需要将当前处理器的状态及一些参数保留在堆栈中,当中断处理完毕以后或程序执行完后返回时,再将堆栈内保存的现场数据予以恢复,以保证原来的程序正确运行。例如各种模式下可以共用寄存器 R0R7,模式切换的前后(即异常或中断发生前后)可能都需要使用它们,如果不保存的话,当异常或中断返回后,原来的程序可能因为这些寄存器中的值被破坏而无法运行。系统堆栈的初始化主要是给各个处理器模式分配堆栈空间。初始始化某种模式的堆栈需先进入这种模式,即将 CPSR 的模式位置为预先定义好的数据,然后将对应模式的堆栈的入口地址赋值给这种模式下的堆栈指针 SP。这样当程序进入异常模式时可以将需要保护的寄存器的值放入 SP 指向的堆栈,当异常处理完毕返回时,从对应的堆栈中将保存的数据恢复,这种入栈出栈的方式能够确保异常返回后程序可正常运行。在分配堆栈空间时需要合理规划堆栈的大小,太小了会使栈泄露,太大会浪费内存。系统需要初始化哪些模式的堆栈还要看实际应用中会使用到哪些模式,一般来说管理模式堆栈必须分配,因为开发板上电或复位时,系统运行的模式是管理模式。应用程序主要在用户模式和系统模式下运行,因此,在这两种模式下对堆栈的要求量会更高一些。如果应用中使用了 IRQ 中断,则 IRQ模式的堆栈需要分配,而且堆栈的大小还要考虑 IRQ 中断的嵌套层数。堆栈是存储在RAM空间中,一般对堆栈的使用方式在根据自己几种模式累加起来对堆栈的总要求量,在RAM空间的尾部预留一部份进行分配。 注意: 在编写堆栈初始化代码时,由于需要切换处理器模式,因此,用户模式无需处理,直接通过系统模式进行处理,最后处理的一个模式最好也是我们接下去要运行处理器模式。 在汇编语言中,注意对寄存器进行手动压栈,而在C语言中,函数嵌套调用时,局部变量(会用到寄存器)编译器会自行压栈处理,且采用的时满递减方式压栈。3.6. RO/RW/ZI初始化3.6.1. 什么是RO,RW,ZI我们编写的源文件(.c 或.s)经过ARM 编译器的编译生成ELF 格式的目标文件(后缀名为.o),目标文件进过ARM 连接器连接以后生成ELF 格式的映像文件(后缀名为.axf),此时的映像文件还包含一些调试信息,我们还需要通过fromelf 工具将其转换成适合在ROM 或RAM 中运行的二进制代码(后缀名为.bin),这时生成的二进制映像文件就可以被烧写入目标板的ROM 或FLASH 中,当目标板上电后可以通过各种方式在ROM 或RAM 中运行。一个可执行程序的映像文件由一个或多个域组成,域分为两种:一种是映像文件在存储器中存放的地址,称为加载域;另一种是映像文件运行时的地址,称为运行域。每个域由一个或3 个输出段组成,每个输出段则由一个或多个输入段组成。输入段包含程序代码、已经初始化的数据、未经初始化的存储区、被初始化为0 的存储区,输入段据此可分为三种属性:RO(只读,包括代码和常量)、RW(可读可写,包括已经初始化的全局变量和静态变量)、ZI(未初始化的变量,需初始化为0), 连接器根据属性将输入段分组,组成不同的输出段。一个输出段是有具有相同属性的输入段组成的,输出段的属性与其中输入段的属性相同,因而输出段也分为三种。域由不同属性的输出段组成,输出段在域中的排列顺序为RO 输出段排在最前,然后是RW 输出段,RW 输出段和RO 输出段可以不连续,最后是ZI 输出段,ZI 输出段是紧接着RW 输出段的(加载域只包含RO、RW 输出段,原因见后述)。可执行镜像一开始一般是存储在系统的ROM 或FLASH 中,RO 段是只读的,在运行的时候我们不能改变它,所以RO 段在运行的时候可以驻留在ROM 或FLASH 中,也可以拷贝到运行速度更快的RAM 中;RW 段在运行的时候,我们需要对其读写,在运行前这一段必须被拷贝至RAM 中;ZI 段为未初始化的全局变量段,只需要在程序运行之前建立ZI 并将其所在区域全部清零即可,因此镜像装。载域不必包含ZI 输出段,但在运行域需要包含ZI,并且ZI 必须处于RAM。通过以上说明,我们知道如果某个镜像只有RO 段的话,程序可以不必拷贝至RAM,但是如果程序包含RW 段的话,RW 段是必需要拷贝至RAM 中的,如果有必要的话还需在RAM 中创建ZI 段,并将其清零。为保证程序的正确执行,而进行必要的数据拷贝和清零,就是应用程序执行环境的初始化。根据以上分析,得出以下结论: ARM程序的组成:一个ARM程序(此处所说的“ARM程序”是指在ARM系统中正在执行的程序,而非保存在ROM中的bin映像(image)文件,这一点清注意区别)包含3部分:RO,RW和ZI。RO(readonly):程序中的指令和常量。RW(read/write):程序中的已初始化变量。ZI(zero init):程序中的未初始化的变量。 ARM映像文件的组成: 所谓ARM映像文件就是指烧录到ROM中的bin文件,也成为image文件。以下用Image文件来称呼它。Image文件包含了RO和RW数据。之所以Image文件不包含ZI数据,是因为ZI数据都是0,没必要包含,只要程序运行之前将ZI数据所在的区域一律清零即可。包含进去反而浪费存储空间。 加载时地址关系 运行时地址关系“加载时地址关系”即为程序烧写进Nor Flash后,程序没有运行时情况。“运行时地址关系”即为启动代码运行后情况。搬移工作由启动代码完成。3.6.2. RO,RW,ZI的初始化RO,RW,ZI的初始化就是为了将程序由加载时域转化为运行时域,它三部份工作要做:1) 将RO段从ROM中拷贝到RAM中2) 将RW段从ROM中拷贝RAM中3) 将RAM中的ZI区进行清零注: 第1)步不是必须的,有些程序存储在NorFlash等可线性寻址的ROM中,可以直接在ROM中执行,这时为了减少RAM的使用量,只将RW段和ZI段搬到RAM中即可。 在RW搬移的过程中要注意字对齐,ZI必须紧接着RW段。4. 系统启动示例IMPORT InitPLL;MPLL和UPLL时钟配置函数IMPORT InitBank;8个BANK口的参数配置函数IMPORT InitStack;各种处理器模式下的堆栈配置函数;IMPORT InitRORWZI;RW与ZI段初始化配置函数IMPORT EOS_Main ;C语言入口函数;*;系统复位的入口代码段,;这个代码编译时固定在0地址的位置;*CODE32;ARM代码AREA RESET,CODE,READONLY;RESET,代码段,只读ENTRY;程序入口;异常向量表LDR PC, =HANDLE_ResetInit ;复位异常LDR PC, =HANDLE_HandlerUndef ;未定义指令异常LDR PC, =HANDLE_HandlerSWI ;软中断异常LDR PC, =HANDLE_HandlerPabort ;取指中止异常LDR PC, =HANDLE_HandlerDabort ;数据中止异常LDR PC, . ;保留LDR PC, =HANDLE_IRQHandle ;IRQ中断异常LDR PC, =HANDLE_HandlerFIQ ;FIQ中断异常;*;复位异常处理函数;处理系统的复位异常,初始化硬件环境,并跳转到C语言;*HANDLE_ResetInit ;();关闭看门狗,;在系统硬件环境初始化过程中需要关闭看门狗;以防止系统不断被复位LDR R0,=rWTCONLDR R1,=0X0STR R1,R0;屏蔽IRQ和FIQ中断位,防止在硬件初始化过程中产生中断 MRS R0,CPSRORR R0,R0,#C_DISABLE_INT_MSKMSR CPSR_c,R0;/配置MPLL和UPLL时钟BL InitPLL;配置8个BANK口的参数BL InitBank;/配置各种处理器模式下的堆栈BL InitStack;RW与ZI段初始化BL InitRORWZI;跳转到C语言的执行环境中BL EOS_Main;*;未定义指令异常处理函数;*HANDLE_HandlerUndef ;();异常处理代码,;这里暂时不处理,进入死循LDR PC, HANDLE_HandlerUndef;*;软中断异常处理函数;*HANDLE_HandlerSWI ;(int nIntNo);异常处理代码,;这里暂时不处理,进入死循LDR PC, HANDLE_HandlerSWI;*;指令中止异常处理函数;*HANDLE_HandlerPabort ;();异常处理代码,;这里暂时不处理,进入死循LDR PC, HANDLE_HandlerPabort;*;数据中止异常处理函数;*HANDLE_HandlerDabort ;();异常处理代码,;这里暂时不处理,进入死循LDR PC, HANDLE_HandlerDabort;*;IRQ中断异常处理函数;*HANDLE_IRQHandle ;();异常处理代码,;这里暂时不处理,进入死循LDR PC, HANDLE_IRQHandle;*;FIQ中断异常处理函数;*HANDLE_HandlerFIQ ;();异常处理代码,;这里暂时不处理,进入死循LDR PC, HANDLE_HandlerFIQ;*;MPLL和UPLL参数配置;*;UPLL = (MDIV_VAL+8)*12MHz)/(PDIV_VAL+2)*2(SDIV_VAL);MPLL = (2*(MDIV_VAL+8)*12MHz)/(PDIV_VAL+2)*2(SDIV_VAL);1 = PDIV_VAL 62, 1 = MDIV_VAL 248;UPLL时钟设置,UPLL只能为96MHz或48MHzUPLL_MDIV_VALEQU0x38UPLL_PDIV_VALEQU0x2UPLL_SDIV_VALEQU0x2UPLL_MDIVEQU(UPLL_MDIV_VAL 12)UPLL_PDIVEQU(UPLL_PDIV_VAL 4)UPLL_SDIVEQU
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年临时工劳动合同样本
- 2025湖南湘潭市市直学校人才引进45人考前自测高频考点模拟试题及1套完整答案详解
- 2025贵州铁路投资集团有限责任公司招聘35人考前自测高频考点模拟试题及答案详解(有一套)
- 2025黑龙江黑河市漠河市公益性岗位招聘18名考前自测高频考点模拟试题附答案详解
- 2025江苏泰州市姜堰区招聘教师20人模拟试卷及一套答案详解
- 2025年上半年四川内江市隆昌市选调120指挥中心人员2人考前自测高频考点模拟试题及答案详解(易错题)
- 2025建筑材料供应商合同书
- 2025年衢州市柯城区医疗卫生事业单位公开引进高层次紧缺人才22人考前自测高频考点模拟试题及答案详解(新)
- 2025年福建省泉州市晋江市农业农村局公开招聘1人模拟试卷及完整答案详解
- 2025吉林长春市市直事业单位招聘高层次人才3人(5号)模拟试卷及完整答案详解1套
- 《电力应急电源装备测试导则》
- 海水鱼类增殖放流记录表格、人工标志、增殖放流验收报告
- 建筑工地节前停工安全检查表
- 动态心电图培训课件
- 微商培训的课件目录
- FZ/T 07025-2022针织行业绿色工厂评价要求
- 小学二年级上册数学练习题
- 德国国家概况
- 内科常见疾病中医诊疗规范诊疗指南2023版
- 全国2022年10月自考05744《食品加工与保藏(专)》真题
- 整本书读写《一颗遗失的扣子》(课件)三年级下册语文统编版
评论
0/150
提交评论