在ARM中,無法直接執行 main 函數,需要額外的啟動代碼來為運行C語言程序設置基本的
運行環境,初始化存儲系統等。為了進行下系統初始化,采用匯編文件作為啟動代碼。
啟動代碼的作用
1.初始化異常向量表
當M0產生異常(中斷)時,需要跳轉到相應的函數中執行。如串口中斷等。。。
需要在啟動文件中構建異常向量表。
2.初始化存儲器系統
3.初始化堆棧
程序使用編譯器分配的空間作為堆棧,而不是按通常的做法爸堆棧分配到RAM的頂端。這樣做的好處一是不必知道RAM頂端的位置,移植更加方便,二是編譯器給出的占用RAM空間的大小就是實際占用的大小,便于控制RAM的分配。
4.初始化有特殊要求的端口、設備
5.初始化應用程序的運行環境
6.改變處理器的運行模式
7.調用主應用程序
當所有執行完畢后,才會調用我們寫的main()函數
參考資料:http://www.zg4o1577.cn/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 ; 串口中斷產生時 將跳轉到 void UART_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 :LNOT::DEF:NO_CRP ; 宏判斷是否定義NO_CRP
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 :DEF:__MICROLIB // “DEF”的用法:DEF:xx就是說xx定義了則為真,否則為假
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 //保存堆起始地址
LDR R1, = (Stack_Mem + Stack_Size) //保存棧的大小
LDR R2, = (Heap_Mem + Heap_Size) // 保存堆得大小
LDR R3, = Stack_Mem // 保存棧頂指針
BX LR
ALIGN // 填充字節使地址對齊
ENDIF
END
|