startup_stm32f407xx.s分析

一、使用的ARM彙編指令

指令名稱 指令作用
EQU 給數字常量取一個符號名,相當於C語言中的define
AREA 彙編一個新的代碼段或者數據段
SPACE 分配內存空間
PRESERVE8 當前文件堆棧需按照8字節對齊
EXPORT 聲明一個具有全局屬性的標號,可被外部文件使用
IMPORT 聲明一個來自外部文件的標號
DCD 以字爲單位分配內存,要求4字節對齊,並要求初始化這些內存
PROC 定義子程序,與ENDP成對使用
ENDP 表示子程序結束
WEAK 弱定義,如果外部文件定義了一個標號,則優先使用外部文件的標號,是ARM僞指令
ALIGN 編譯器對指令或數據的存放地址進行對齊,缺省表示4字節對齊,是ARM僞指令
IF,ELSE,ENDIF 彙編條件分支語句,同C語言的類似
LDR 從存儲器中加載字到一個寄存器中
B 跳轉到一個標號
BL 跳轉到由寄存器/標號給出的地址,並保存跳轉前的下條指令至LR中
BX 跳轉到由寄存器/標號給出的地址,並根據寄存器的LSE確定處理器的狀態
BLX 跳轉到由寄存器/標號給出的地址,並根據寄存器的LSE確定處理器的狀態,同時保存跳轉前的下條指令至LR中
END 到達文件的末尾,文件結束

二、文件的主要功能

  • 堆棧以及堆的初始化
  • 初始化中斷向量表
  • 調用Reset_Handler
  • 其他代碼

三、文件內容剖析

Stack_Size      EQU     0x00000400

                AREA    STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem       SPACE   Stack_Size
__initial_sp

初始化棧:
開闢棧大小爲0x00000400(1KB),名字爲STACK,NOINIT不初始化,可讀可寫,8(2^3)字節對齊。 棧的作用是用於局部變量,函數調用,函數形參等的開銷,棧的大小不能超過內部SRAM 的大小。如果編寫的程序比較大,定義的局部變量很多,那麼就需要修改棧的大小。如果某一天,你寫的程序出現了莫名奇怪的錯誤,並進入了硬fault 的時候,這時你就要考慮下是不是棧不夠大而溢出了。 

Heap_Size       EQU     0x00000200

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem        SPACE   Heap_Size
__heap_limit

初始化堆:
開闢堆大小爲0x00000200(512字節),名字爲HEAP,不初始化,可讀可寫,8字節對齊。堆主要用於動態內存的分配。

PRESERVE8
THUMB

指定當前文件的堆棧按照8字節對齊,且後面的指令兼容THUMB指令

AREA    RESET, DATA, READONLY
EXPORT  __Vectors
EXPORT  __Vectors_End
EXPORT  __Vectors_Size

定義一個名爲RESET的數據段,只讀。並聲明 __Vectors、__Vectors_End 和__Vectors_Size 三個具有全局屬性的標號,可供外部的文件調用。

__Vectors       DCD     __initial_sp               ; Top of Stack
                DCD     Reset_Handler              ; Reset Handler
                DCD     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     HASH_RNG_IRQHandler               ; Hash and Rng
                DCD     FPU_IRQHandler                    ; FPU
            
__Vectors_End

__Vectors_Size  EQU  __Vectors_End - __Vectors

__Vectors 爲向量表起始地址,__Vectors_End 爲向量表結束地址,兩個相減即可算出向量表大小。向量表從FLASH 的0地址開始放置,以4個字節爲一個單位,地址0 存放的是棧頂地址,0X04存放的是復位程序的地址,以此類推。

AREA    |.text|, CODE, READONLY

定義一個名爲.text的代碼段,只讀。

Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
        IMPORT  SystemInit
        IMPORT  __main

                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP

復位子程序是系統上電後第一個執行的程序,調用SystemInit函數初始化系統時鐘,然後調用C庫函數__main,最終調用main函數去到C的世界。

NMI_Handler     PROC
                EXPORT  NMI_Handler                [WEAK]
                B       .
                ENDP
HardFault_Handler\
                PROC
                EXPORT  HardFault_Handler          [WEAK]
                B       .
                ENDP
......
                B       .
                ENDP

B		.表示無限循環
在啓動文件裏面已經幫我們寫好所有中斷的中斷服務函數,跟我們平時寫的中斷服務函數不一樣的就是這些函數都是空的,真正的中斷復服務程序需要我們在外部的C 文件裏面重新實現,這裏只是提前佔了一個位置而已。

如果我們在使用某個外設的時候,開啓了某個中斷,但是又忘記編寫配套的中斷服務程序或者函數名寫錯,那當中斷來臨的時,程序就會跳轉到啓動文件預先寫好的空的中斷服務程序中,並且在這個空函數中無限循環,即程序就死在這裏。

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

END

用戶堆棧初始化由C庫函數__main完成,__MICROLIB由KEIL裏面開啓,__use_two_region_memory由用戶自己實現。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章