天天看點

淺析STM32啟動過程和啟動檔案了解STM32的啟動過程STM32啟動檔案

了解STM32的啟動過程

我們平時在使用STM32時,寫程式一般都是直接從main函數開始,初始化系統時鐘以及各個外設,然後進入while循環,執行邏輯功能函數。但是知不知道在main函數之前,晶片都做了什麼呢?讓我們大緻了解一下STM32的啟動過程。

首先看一下CM3權威指南對于複位的描述:

淺析STM32啟動過程和啟動檔案了解STM32的啟動過程STM32啟動檔案

意思大緻就是複位後,會從0x0000 0000位址取出棧的初始值(該值在後面初始化棧會用到),從0x0000 0004取出複位向量指派PC指針,然後程式跳轉到複位函數的入口位址,開始往後執行程式。

我們使用的是從Flash啟動的方式,是以根據存儲映射是位址從從0x00000000映射到0x08000000。是以當STM32晶片上電或複位時,會從0x0800 0004處,取出四個位元組指派給PC指針,進而程式跳轉至複位函數的入口位址。這裡我們看一下調試狀态下的彙程式設計式:先進去軟體仿真模式,在彙編視窗,定位到0x0800 0000位址處

淺析STM32啟動過程和啟動檔案了解STM32的啟動過程STM32啟動檔案

可以看到,位址0x0800 0000處存放的是0x2000 0748(該晶片為小端模式,高位元組存放在高位址),0x0800 0004存放的是0x0800 01CD。是以,這個0x0800 01CD應該就是我們複位函數的入口位址了。我們繼續定位程式到該位址:

淺析STM32啟動過程和啟動檔案了解STM32的啟動過程STM32啟動檔案

仔細一看,會發現找不到0x0800 01CD,隻有0x0800 01CC。沒錯,複位函數的入口就是0x0800 01CC。且看CM3權威指南對于複位向量的描述:

淺析STM32啟動過程和啟動檔案了解STM32的啟動過程STM32啟動檔案

LSB必須為1,就是位址的bit0必須為1,是以0x0800 01CC存放的形式會是0x0800 01CD。這裡猜測由于STM32是32bit的,取址時會四位元組對齊,是以PC指針會跳轉至0x0800 01CC處而不是0x0800 01CD處。後面的内容我們可以看到,就是執行複位函數裡的内容,SystemInit函數和__main函數,我們下面來詳細看一下啟動檔案。

STM32啟動檔案

順着上面的内容,我們暫時不看其他地方,直接來到複位函數吧

Reset_Handler   PROC
                EXPORT  Reset_Handler             [WEAK]
                IMPORT  __main
                IMPORT  SystemInit
                LDR     R0, =SystemInit
                BLX     R0               
                LDR     R0, =__main
                BX      R0
                ENDP
           

PROC和ENDP表示函數定義的開頭和結尾,中間時函數定義内容

EXPORT表示該标号可以供外部其他子產品調用

IMPORT表示定義來自外部,類似C語言的extern

接下來的兩行表示程式調用SystemInit函數,我們可以全局搜尋該函數名,會發現該函數的定義位于ST提供的庫檔案system_stm32f10x.c中:

淺析STM32啟動過程和啟動檔案了解STM32的啟動過程STM32啟動檔案

該函數對時鐘源、系統時鐘等進行了配置,具體可以檢視對應的寄存器含義。

繼續看複位函數,後面是__main函數,這個函數就複雜了,并不是我們main函數的main,它做了很多事情,最後才調用main函數的main。看一下彙編:

淺析STM32啟動過程和啟動檔案了解STM32的啟動過程STM32啟動檔案

可以看出,要去0x0800 01F8處取出值作為位址,并跳轉到該位址。找到0x0800 01F8,該位址存放的值為0x0800 0131:

淺析STM32啟動過程和啟動檔案了解STM32的啟動過程STM32啟動檔案

繼續,定位到0x0800 0131位址處:

淺析STM32啟動過程和啟動檔案了解STM32的啟動過程STM32啟動檔案

我們會發現調用了__scatterload函數,查了一下map檔案,發現該函數來自__scatter.o,應該是編譯器帶的庫有的。後面的程式還會調用很多其他庫裡的相關函數。

淺析STM32啟動過程和啟動檔案了解STM32的啟動過程STM32啟動檔案

具體的彙程式設計式就不分析了。這裡總結一下__main完成的工作:

1.初始化.data區和.bss區

2.初始化堆棧

3.跳轉到main函數。

大緻說到這裡吧,有些地方還沒有去詳細研究,不太了解。

繼續閱讀