在ARM中,无法直接执行 main 函数,需要额外的启动代码来为运行C语言程序设置基本的 运行环境,初始化存储系统等。为了进行下系统初始化,采用汇编文件作为启动代码。 启动代码的作用 1.初始化异常向量表 当M0产生异常(中断)时,需要跳转到相应的函数中执行。如串口中断等。。。 需要在启动文件中构建异常向量表。 2.初始化存储器系统 3.初始化堆栈 程序使用编译器分配的空间作为堆栈,而不是按通常的做法爸堆栈分配到RAM的顶端。这样做的好处一是不必知道RAM顶端的位置,移植更加方便,二是编译器给出的占用RAM空间的大小就是实际占用的大小,便于控制RAM的分配。 4.初始化有特殊要求的端口、设备 5.初始化应用程序的运行环境 6.改变处理器的运行模式 7.调用主应用程序 当所有执行完毕后,才会调用我们写的main()函数 参考资料:http://www.51hei.com/bbs/dpj-30365-1.html startup_LPC11xx.s : ;/***************************************************************************** ; * @file: startup_LPC11xx.s ; * @purpose: CMSIS Cortex-M0 Core Device Startup File ; * for the NXP LPC11xx Device Series ; * @version: V1.0 ; * @date: 25. Nov. 2008 ; *------- <<< Use Configuration Wizard in Context Menu >>> ------------------ ; * ; * Copyright (C) 2008 ARM Limited. All rights reserved. ; * ARM Limited (ARM) is supplying this software for use with Cortex-M0 ; * processor based microcontrollers. This file can be freely distributed ; * within development tools that are supporting such ARM based processors. ; * ; * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED ; * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF ; * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. ; * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR ; * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. ; * ; *****************************************************************************/ ; <h> Stack Configuration ; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8> ; </h> Stack_Size EQU 0x00000100 ; 定义Stack_Size 标号为0x100的空间作为栈空间 AREA STACK, NOINIT, READWRITE, ALIGN=3 Stack_Mem SPACE Stack_Size ; 为栈分配内存空间,并初始化为0 __initial_sp ; <h> Heap Configuration ; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8> ; </h> Heap_Size EQU 0x00000000 ; 堆大小定义为 0 AREA HEAP, NOINIT, READWRITE, ALIGN=3 __heap_base Heap_Mem SPACE Heap_Size ; 为堆分配内存空间,并初始化为0 __heap_limit ; 堆地址的标号 PRESERVE8 ; 当前堆栈保持8字节对齐 THUMB ; 指示编译器为 thumb 指令 ; 定义异常向量表 ; Vector Table Mapped to Address 0 at Reset 向量表映射到复位地址 0 AREA RESET, DATA, READONLY ; 声明数据段RESET,放到数据段中为于0地址,其实放在CODE区 ; 该数据段内存单元只读 EXPORT __Vectors ; 声明一个全局的标号,该标号可在其他的文件中引用 /* DCD伪指令用于分配一片连续的字存储单元并用伪指令中指定的表达式初始化。其中,表达式可以为程序标号或数字表达式。DCD也可用“&”代替。 */ __Vectors DCD __initial_sp ; Top of Stack ; 给__initial_sp分配4字节32位的地址 DCD Reset_Handler ; Reset Handler ;给标号Reset_Handler分配地址 DCD NMI_Handler ; NMI Handler ; 给标号NMI_Handler分配地址 DCD HardFault_Handler ; Hard Fault Handler DCD MemManage_Handler ; MPU Fault Handler DCD BusFault_Handler ; Bus Fault Handler DCD UsageFault_Handler ; Usage Fault Handler DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD SVC_Handler ; SVCall Handler DCD DebugMon_Handler ; Debug Monitor Handler DCD 0 ; Reserved ;DCD PendSV_Handler ; PendSV Handler IMPORT OS_CPU_PendSVHandler DCD OS_CPU_PendSVHandler ;DCD SysTick_Handler ; SysTick Handler IMPORT OS_CPU_SysTickHandler DCD OS_CPU_SysTickHandler ; DCD伪指令用于分配一片连续的字存储单元并用指定的表达式初始化 ; External Interrupts DCD WAKEUP_IRQHandler ; 15 wakeup sources for all the DCD WAKEUP_IRQHandler ; I/O pins starting from PIO0 (0:11) DCD WAKEUP_IRQHandler ; all 40 are routed to the same ISR DCD WAKEUP_IRQHandler DCD WAKEUP_IRQHandler DCD WAKEUP_IRQHandler DCD WAKEUP_IRQHandler DCD WAKEUP_IRQHandler DCD WAKEUP_IRQHandler DCD WAKEUP_IRQHandler DCD WAKEUP_IRQHandler DCD WAKEUP_IRQHandler DCD WAKEUP_IRQHandler ; PIO1 (0:11) DCD CAN_IRQHandler ; CAN DCD SSP1_IRQHandler ; SSP1 DCD I2C_IRQHandler ; I2C DCD TIMER16_0_IRQHandler ; 16-bit Timer0 DCD TIMER16_1_IRQHandler ; 16-bit Timer1 DCD TIMER32_0_IRQHandler ; 32-bit Timer0 DCD TIMER32_1_IRQHandler ; 32-bit Timer1 DCD SSP0_IRQHandler ; SSP0 DCD UART_IRQHandler ; UART ; 串口中断产生时 将跳转到 voidUART_IRQHandler(void) DCD USB_IRQHandler ; USB IRQ DCD USB_FIQHandler ; USB FIQ DCD ADC_IRQHandler ; A/D Converter DCD WDT_IRQHandler ; Watchdog timer DCD BOD_IRQHandler ; Brown Out Detect DCD FMC_IRQHandler ; IP2111 Flash Memory Controller DCD PIOINT3_IRQHandler ; PIO INT3 DCD PIOINT2_IRQHandler ; PIO INT2 DCD PIOINT1_IRQHandler ; PIO INT1 DCD PIOINT0_IRQHandler ; PIO INT0 IF ![]() ![]() AREA |.ARM.__at_0x02FC|, CODE, READONLY ; 自定义只读代码段 CRP_Key DCD 0xFFFFFFFF ; 加密等级 ENDIF AREA |.text|, CODE, READONLY ; 声明代码段|.text|,只读 ; Reset Handler ; 复位入口子函数 复位后执行的函数 Reset_Handler PROC ; PROC:子程序开始伪指令 EXPORT Reset_Handler [WEAK] IMPORT __main ; __main()是编译系统提供的一个函数 LDR R0, =__main ; 负责完成库函数的初始化和初始化应用程序执行环境 BX R0 ; 跳转到编译系统的__main(),最后自动跳转到用户程序的main() ENDP ; 子程序结束 ; Dummy Exception Handlers (infinite loops which can be modified) NMI_Handler PROC EXPORT NMI_Handler [WEAK] B . ENDP HardFault_Handler\ PROC EXPORT HardFault_Handler [WEAK] B . ENDP MemManage_Handler\ PROC EXPORT MemManage_Handler [WEAK] B . ENDP BusFault_Handler\ PROC EXPORT BusFault_Handler [WEAK] B . ENDP UsageFault_Handler\ PROC EXPORT UsageFault_Handler [WEAK] B . ENDP SVC_Handler PROC EXPORT SVC_Handler [WEAK] B . ENDP DebugMon_Handler\ PROC EXPORT DebugMon_Handler [WEAK] B . ENDP PendSV_Handler PROC EXPORT PendSV_Handler [WEAK] B . ENDP SysTick_Handler PROC EXPORT SysTick_Handler [WEAK] B . ENDP Default_Handler PROC EXPORT WAKEUP_IRQHandler [WEAK] EXPORT CAN_IRQHandler [WEAK] EXPORT SSP1_IRQHandler [WEAK] EXPORT I2C_IRQHandler [WEAK] EXPORT TIMER16_0_IRQHandler [WEAK] EXPORT TIMER16_1_IRQHandler [WEAK] EXPORT TIMER32_0_IRQHandler [WEAK] EXPORT TIMER32_1_IRQHandler [WEAK] EXPORT SSP0_IRQHandler [WEAK] EXPORT UART_IRQHandler [WEAK] EXPORT USB_IRQHandler [WEAK] EXPORT USB_FIQHandler [WEAK] EXPORT ADC_IRQHandler [WEAK] EXPORT WDT_IRQHandler [WEAK] EXPORT BOD_IRQHandler [WEAK] EXPORT FMC_IRQHandler [WEAK] EXPORT PIOINT3_IRQHandler [WEAK] EXPORT PIOINT2_IRQHandler [WEAK] EXPORT PIOINT1_IRQHandler [WEAK] EXPORT PIOINT0_IRQHandler [WEAK] WAKEUP_IRQHandler CAN_IRQHandler SSP1_IRQHandler I2C_IRQHandler TIMER16_0_IRQHandler TIMER16_1_IRQHandler TIMER32_0_IRQHandler TIMER32_1_IRQHandler SSP0_IRQHandler UART_IRQHandler USB_IRQHandler USB_FIQHandler ADC_IRQHandler WDT_IRQHandler BOD_IRQHandler FMC_IRQHandler PIOINT3_IRQHandler PIOINT2_IRQHandler PIOINT1_IRQHandler PIOINT0_IRQHandler B . ENDP ALIGN ; 添加补丁字节满足对齐 ; User Initial Stack & Heap 用户初始化的堆栈 IF ![]() EXPORT __initial_sp //则将栈顶定制 EXPORT __heap_base // 堆起始地址赋予全局属性 EXPORT __heap_limit //堆末端界限地址赋予全局属性,使外部程序可调用 ELSE //如果没有定义__MICROLIB,则使用默认的C运行时库 IMPORT __use_two_region_memory // 通知编译器要使用的标号在其他文件//__use_two_region_memory EXPORT __user_initial_stackheap // 声明全局标号__user_initial_stackheap,这样外程序也可调用此标号 //则进行堆栈和堆的赋值,在__main函数执行过程中调用 //如果了使用默认的C库,程序启动过程中不会执行标号下//的代码 /************************************************************************************************************************************************************** _user_initial_stackheap() 返回: · r0 中的堆基址 · r1 中的堆栈基址,即堆栈区中的最高地址 · r2 中的堆限制 · r3 中的堆栈限制,即堆栈区中的最低地址。 有单区模型和双区模型。 单区模型:(r0,r1)是单个堆栈和堆区。r1 大于 r0,并忽略 r2和r3。 r0--r1这一块内存区域被堆和栈共用,堆从r0向上生长,栈从r1向下生长。 双区模型:(r0, r2)是初始堆,(r3, r1) 是初始堆栈。r2 大于或等于r0,r3小于r1。 堆和栈分别指定了单独的内存区域。 **************************************************************************************************************************************************************/ __user_initial_stackheap // 标号__user_initial_stackheap,表示拥护堆栈初始化程序入口 //则进行堆栈和堆得赋值,在__main函数执行过程中调用 LDR R0, = Heap_Mem //保存堆起始地址 ENDIF END |
欢迎光临 迅维网 (https://www.chinafix.com/) | Powered by Discuz! X3.4 |