STM32 單片機啟動流程
剛接觸ARM的cortex-m系列單片機時,被告知一切都從main() 函式開始,要將程式寫在main()函式中,而仿真時也貌似是從main() 函式開始的,以STM32F103為例,

后來了解到全域變數是在main()函式之前初始化的,MDK默認情況下勾選下面選項,跳過了啟動的匯編部分代碼,直接進入了main() 函式.

實際起始位置

在cortex-m系列中,中斷向量表存放在 Flash 開始部分,Flash中第一個字存放堆疊頂指標,第二個字存放復位中斷服務函式入口地址,其他中斷服務函式入口地址依次存放在Flash中,

MCU上電后,會將Flash中的第一個字加載到R13 MSP暫存器中,第二個字加載到R15 PC暫存器中,

R13:堆疊頂指標暫存器SP
SP暫存器有兩個,MSP或者PSP,PSP是為了RTOS特意設定的,如果使用RTOS,則在RTOS的任務中就是使用的PSP,在中斷服務函式中則使用MSP,如果不適用RTOS,則默認一直使用PSP,

在MCU中,RAM只是負責暫存資料,真正的運算是在暫存器中完成的,例如要對兩個變數進行加法運算,就需要將兩個變數的值從RAM中取出存入暫存器中,然后操作暫存器進行計算,最后將計算結果存入RAM中,因此常說的在進入子函式或者中斷服務函式時需要保存現場,其實也就是保存暫存器中的值,將暫存器值保存在堆疊中,

MSP暫存器存放堆疊頂指標,堆疊中存放區域變數、函式引數以及進入子函式、中斷服務函式前暫存器的值,當從子函式或者中斷服務函式中跳出時,會從堆疊中加載暫存器值,也就是恢復現場,確保程式可以正常執行,平時盡量不讓使用遞回就是為了防止多次呼叫自身,多次保存現場導致堆疊溢位,

入堆疊和出堆疊操作由編譯器自動生成代碼,但是入堆疊時默認只會將R0-R3入堆疊,如果中斷服務函式過于復雜,則編譯器也會將R4-R11入堆疊,這也就是為什么中斷服務函式盡量簡短的原因之一,

R15:程式計數暫存器PC
PC暫存器指向當前的程式地址,如果修改它的值,就能改變程式的執行流(很多高級技巧就在這里面)

上電時將中斷向量表中的第二個字加載到PC暫存器中,也就是讓程式跳轉到復位中斷服務函式中,


不過復位中斷服務函式是一個匯編函式,

復位中斷服務函式中呼叫了SystemInit()函式,該函式主要作用是設定中斷向量表的偏移地址,也就是說中斷向量表位置是可變的,當使用BOOT后,就需要在APP修改該偏移地址,

接著復位中斷服務函式跳轉到__main()函式中,__main()和我們平時說的main()函式是有區別的,

RAM掉電會丟失資料,在上電后,RAM中的資料是不確定的,在運行main()函式之前需要將RAM中的資料初始化,也就是下圖左邊到右邊的程序,將flash中的RW資料加載到RAM中,并將RAM中的ZI段資料進行初始化操作,MDK中__main()函式幫我們自動完成了這個操作,也就是所謂的準備C語言環境,C語言環境準備好之后會跳到 main() 函式,

最后,其實還少說了一個,在上電后最先執行的其實是系統bootLoad(出廠時,官方固化在單片機中的一段代碼,用戶無法修改的),在STM32中,常用的串口下載,DFU就是系統bootLoad中的功能,系統bootLoad執行完畢后才是我們上面說的哪些,文章中的圖來自《Cortex-M3 權威指南》
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/328206.html
標籤:其他
