STM32入門系列-啟動文件介紹


在啟動文件內部使用的都是匯編語言,這個文件的作用是負責執行微控制器從“復位”到“開始執行 main 函數”中間這段啟動時間所必須進行的工作。它完成的具體工作有:

  • 初始化堆棧指針SP=_initial_sp

  • 初始化PC指針=Reset_Handler

  • 初始化中斷向量表

  • 配置系統時鍾

  • 調用C庫函數_main初始化用戶堆棧,從而轉向我們用戶應用程序的main。

匯編指令

    打開STM32的啟動文件會發現,里面全部都是匯編語句,對於匯編指令不了解的朋友來說可能一頭霧水。下面我們按照啟動文件內指令出現的順序來介紹,相信可以了解到大概情況。

    EQU:給數字常量取一個符號名, 相當於C語言中的預處理命令define。其常用格式如下:


Stack_Size EQU 0x00000400


    表示將0x00000400這個數值,用Stack_Size名代替。

    AREA:匯編一個新的代碼段或者數據段。常用格式如下:


AREA STACK, NOINIT, READWRITE, ALIGN=3


    表示匯編一個數據段,名字是STACK,NOINIT表示不初始化,READWRITE表示可讀可寫,ALIGN表示字節對齊,通常后面會賦一個立即數,比如ALIGN=3表示的就是2^3字節對齊,即8字節對齊。

    SPACE:分配一定大小的內存空間,單位為字節。常用格式如下:


Stack_Mem SPACE Stack_Size


    表示給Stack_Mem分配一個Stack_Size大小的內存空間。通常它后面還會跟隨一個__initial_sp語句,表示棧的結束地址,即棧頂地址,因為棧是由高向低生長的。

    PRESERVE8:當前文件堆棧需按照8字節對齊。格式:直接寫此指令即可。

    THUMB:表示后面指令兼容THUMB指令。在ARM以前的指令集中有16位的THUMBM指令,現在Cortex-M系列使用的都是THUMB-2指令集,THUMB-2是32位的,兼容16位和32位的指令,是THUMB的超級版。格式:直接寫此指令即可。

    EXPORT:聲明一個具有全局屬性的標號,可被外部文件使用。常用格式如下:


EXPORT __Vectors


    表示__Vectors標號具有全局屬性,外部文件可以調用它。

    DCD:以字為單位分配內存, 要求4字節對齊, 並要求初始化這些內存。常用格式如下:


DCD Reset_Handler ; Reset Handler


    表示給Reset_Handler名稱的地址分配內存並初始化, 這個名稱地址可以在“STM32F4xx中文參考手冊”-“中斷和事件”-“中斷和異常向量”章節中找到。在那個函數名后面還有一個“;”, 在匯編程序中“;”即注釋,和C語言中的//類似效果。在后面的學習中會接觸很多的中斷函數,這些中斷函數名都可在DCD這部分找到。

    PROC:定義子程序。常用格式:


; Reset handler

Reset_Handler PROC

            EXPORT Reset_Handler [WEAK]

            IMPORT SystemInit

            IMPORT __main

                            LDR R0, =SystemInit

                            BLX R0

                            LDR R0, =__main

                            BX R0

                            ENDP


    表示定義一個全局的子程序Reset_Handler,需與ENDP成對使用,表示子程序結束。在


EXPORT Reset_Handler     [WEAK]


后面有一個[WEAK],這個是弱定義,如果外部文件聲明了一個標號,則優先使用外部文件定義的標號,如果外部文件沒有定義也不出錯。要注意的是:這個並不是ARM的指令,是編譯器的。

    LDR:從存儲器中加載字到一個寄存器中。常用格式:


LDR R0, =SystemInit


    BLX:跳轉到由寄存器給出的地址,並根據寄存器的LSE確定處理器的狀態,還要把跳轉前的下條指令地址保存到LR。常用格式:


BLX R0


    BX:跳轉到由寄存器/標號給出的地址,不用返回。常用格式:


BX R0


    IMPORT:聲明標號來自外部文件,和C語言中的extern關鍵字類似。


IMPORT SystemInit

IMPORT __main


    上述代碼中表示聲明SystemInit和main為外部文件,所以 在創建寄存器模板的時候寫一個SystemInit()空函數。如果想修改main.c文件中的main函數名,在這個地方就可以改動,然后后面


LDR R0, =__main


中的main也需要改動,對匯編不了解的不建議改動。

    B:跳轉到一個標號。常用格式如下:


B .


    在B后面有一個“.”,在匯編語言中表示循環。這句話的意思就是說跳進了循環。

    IF,ELSE,ENDIF:匯編條件分支語句,與C語言的if else類似。其常用格式:


IF :DEF:__MICROLIB

EXPORT __initial_sp

EXPORT __heap_base

EXPORT __heap_limit

ELSE

IMPORT __use_two_region_memory

EXPORT __user_initial_stackheap

ENDIF


END:到達文件的末尾,文件結束。

    到這里啟動文件指令就介紹完了, 有的朋友在學習過程中還會遇到其他的匯編指令,那么怎么查找它們的功能和用法呢?其實很簡單,KEIL5軟件內已經給我們提供了幫組文檔,打開Help選項就會彈出幫助文檔,如下圖所示。

 

 

    幫助文檔的界面如下圖所示,如果要查找AREA指令,只需要選擇搜索,輸入要搜索的指令,選擇列出主題即可。選擇對應的指令,右側就會顯示指令的具體介紹和格式說明。

 

 

堆棧

    學習過C語言的朋友對堆棧這一詞很熟悉。在啟動文件開始處就定義了一堆棧的大小,代碼如下:


;棧空間的開辟

Stack_Size EQU 0x00000400

AREA STACK, NOINIT, READWRITE, ALIGN=3

Stack_Mem SPACE Stack_Size

__initial_sp ;棧的結束地址

;堆空間的開辟

Heap_Size EQU 0x00000200

AREA HEAP, NOINIT, READWRITE, ALIGN=3

__heap_base

Heap_Mem SPACE Heap_Size

__heap_limit ;堆的結束地址


    在程序開頭開辟了一個0x00000400即1KB的Stack_Size棧空間。 棧主要用於存放函數的參數值、局部變量的值等,其操作方式類似於數據結構中的棧。棧的大小不能超過內部RAM的大小。假如開發的程序占用的RAM比較大,局部變量使用的比較多,那么可以在啟動文件內修改這個Stack_Size值。

    如果程序出現了莫名其妙的錯誤,並進入了硬fault的時候,你就要考慮下是不是棧不夠大,溢出了的問題。通常我們修改最多的還是棧值。

    程序緊接着又開辟了一個0x00000200即512字節的Heap_Size堆空間。堆中的內存一般由程序員分配和釋放,若程序員不釋放,程序結束時可能由操作系統回收。分配方式類似於數據結構中的鏈表。堆和棧生長方式是相反的,堆是由低向高生長的,而棧是由高向低生長的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM