提示:若轉載請備注來源,謝謝
文章目錄
- 啟動檔案
- 1. 什么是啟動代碼
- 2. 啟動代碼主要干了什么
- 啟動檔案分析
- 一、設定堆疊
- 二、定義中斷向量表
- 三、初始化系統時鐘
- 總結
啟動檔案
1. 什么是啟動代碼
啟動代碼是系統上電或者復位后運行的第一段代碼,是進入C 語言的main 函式之前需要執行的那段匯編代碼,或者說用戶程式運行之前對系統硬體及軟體環境進行必要的初始化并在最后使程式跳轉到用戶程式,
將啟動檔案理解為一種描述性的代碼,不要拘泥于它的實作機制,我之前一直在想啟動代碼中匯編代碼的執行順序,后來沒明白,估計和keil工具有關系,只需要記住一個道理,程式上電執行的第一條代碼(我們可以控制的代碼),就是啟動檔案中Reset Handler函式,Reset Handler函式 的地址存放在flash的0x00000004處,
2. 啟動代碼主要干了什么
對于 Cortex-M系列的芯片而言,啟動代碼大同小,明白一個幾乎所有的也就都明白了,
- 設定堆疊
- 定義中斷向量表
- 初始化系統時鐘(Reset_Handler中做)
- 初始化堆疊,有的啟動代碼不一定做(Reset_Handler中做)
- 執行_main,準備c語言的運行環境,初始化程式計數器指標PC指向main,進而來到c語言的世界
啟動檔案分析
一、設定堆疊
; <h> Stack Configuration
; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
Stack_Size EQU 0x00000800
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
; <h> Heap Configuration
; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
Heap_Size EQU 0x00000100
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
PRESERVE8
THUMB
以上僅僅定義了堆疊的大小,堆疊的起始地址在keil中設定方式有兩種,
第一種:

第二種,分散加載檔案(將keil的Use Memory Layout from Target Dialog去掉勾選就會有該檔案),在實際專案中,我通常使用該檔案,可以理解問鏈接檔案

在上圖(第一幅圖片中),啟動檔案的最后幾行,有關于Use MicoLIB的描述,還有關于堆疊的設定,代碼為,主要是初始化堆疊的地址范圍:
;*******************************************************************************
; User Stack and Heap initialization
;*******************************************************************************
IF :DEF:__MICROLIB
EXPORT __initial_sp
EXPORT __heap_base
EXPORT __heap_limit
ELSE
IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap
__user_initial_stackheap
LDR R0, = Heap_Mem
LDR R1, =(Stack_Mem + Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
BX LR
ALIGN
ENDIF
二、定義中斷向量表
1. 當內核回應了一個發生的例外后,對應的例外服務例程(ESR)就會執行,為了決定 ESR的入口地址, 內核使用了―向量表查表機制‖(是ARM的實作機制),這里使用一張向量表,向量表其實是一個WORD(32 位整數)陣列,每個下標對應一種例外,該下標元素的值則是該 ESR 的入口地址,
2. 向量表在地址空間中的位置默認存放在0x00000000處,但是還可以設定,通過 NVIC 中的一個重定位暫存器來指出向量表的地址,
代碼為:
; Vector Table Mapped to Address 0 at Reset
AREA RESET, DATA, READONLY
EXPORT __Vectors
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_IRQHandler ; NMI Handler
DCD HardFault_IRQHandler ; Hard Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
......
......
AREA |.text|, CODE, READONLY
附加:常常在涉及到升級loader中使用
- 向量表重定位 + 跳轉代碼如下:
__asm void SoftReset(u32 address)
{
LDR R1, =0xE000ED08 // 0xE000ED08 重定位地址
STR R0, [R1, #0] // R0為形參address
/* 重定位完后,向量表地址為address */
LDR r1, [r0] // address內前4個直接存放的 Top of Stack
msr MSP,r1 // 給MSP賦值
ADDS r0, r0, #4 // Reset_Handler 的地址
LDR r1, [r0]
NOP
BX R1 // 執行 Reset_Handler
NOP
NOP
NOP
}
- 若僅僅想實作向量表重定位,例如將向量表定位到0x00000200,代碼如下:
// SCB->VTOR就等于 0xE000ED08
//SCB->VTOR = 0x00000000; // 等價于0xE000ED08 = 0x00000000;
SCB->VTOR = 0x00000200;
三、初始化系統時鐘
還是要在重申一下,復位子程式Reset_Handler是系統上電后第一個執行的程式,這里分析兩個Reset handler,一個是STM32 demo上的,一個是我們使用的thk88芯片的
stm32代碼為:
; Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT __main
IMPORT SystemInit
LDR R0, =SystemInit // 系統初始化,里面包含了初始化時鐘
BLX R0
LDR R0, =__main // 最后跳轉到main()
BX R0
ENDP
thk88代碼為
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT main
; 開啟內部時鐘30M
LDR R3, =SCUBASEADDR
LDR R0, =0x00000000
STR R0, [R3,#SCUSCK]
LDR R0, =0x00000000
STR R0, [R3,#SCUINCKD]
; 關閉USB PHY,禁止DP上拉電阻
LDR R0, =0x00000100
STR R0, [R3, #SCUCM3] ;OPEN USB CLK
LDR R2, =USBBASEADDR
LDR R0, =0x00000001
STR R0, [R2,#USBPCON] ; 關閉USB PHY
LDR R0, =0x00000000
LDR R2, =USBPHYCON
STR R0, [R2] ;禁止DP上拉
;STR R0, [R2,#USBPHYCON] ;禁止DP上拉
; 屏蔽 NMI 中斷
LDR R0, =0XFFFFFFFF
LDR R2, =SCUNMI
STR R0, [R3,R2]
; DMA使用event方式
LDR R2, = 0x40000100 ;SCUEVTSET1 = 0x02;DMA event mode
LDR R0, = 0x00000002
STR R0, [R2]
;初始化用到的RAM區,4位元組對齊,包括RW和ZI區域
BL CLEAR_ZI
IMPORT __main
LDR R0,= __main
BX R0
ENDP
每款芯片的啟動代碼大同小異,熟悉一個其他的都可以看懂,
總結
具體啟動流程如圖,兩種方式
- 啟動流程1(使用標準庫,不使用Microlib)如下圖:

- 啟動流程2(使用Microlib)如下圖:

假設STM32被設定為從內部FLASH啟動(這也是最常見的一種情況),中斷向量表起始地位為0x00000000(映射到0x8000000,兩個是一個東西),則堆疊頂地址存放于0x8000000處,而復位中斷服務入口地址存放于0x8000004處(復位地址在堆疊頂地址4位元組后),當STM32上電后,遇到復位信號,則從0x80000004處取出復位中斷服務入口地址,繼而執行復位中斷服務程序,然后跳轉__main函式,最后進入mian函式,來到C的世界,
重申:
- 絕大部分ARM-M協議的芯片,復位之后先進入廠商boot,此時所有的用戶均無法接入處理器;廠商boot主要負責芯片最初級的初始化,對MCU進行一些差異性設定等,BOOT完成后,會把主動權交給用戶,也就是啟動代碼;
- 啟動代碼(執行匯編語言不需要此啟動代碼),在啟動檔案中,會設定MSP(主堆疊指標)和PC(程式計數器)的值,MSP的地址默認是0x00000000,PC的地址默認是0x00000004,這兩個地址可以通過CORTEX-M中的VTOR暫存器來進行重映射,修改,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/246619.html
標籤:其他
