【STM32芯片啟動流程】——結(jié)合具體啟動文件和hex文件分析
一、前言
最近想把MCU相關(guān)的知識梳理一遍,希望加深自己對相關(guān)知識的理解,同時也作為備忘錄提醒自己。首先是STM32的啟動過程,理解這個過程是學(xué)習(xí)IAP和OTA功能以及深入stm32內(nèi)核的基礎(chǔ)。
二、總體流程介紹
- 由boot引腳(boot0,boot1)選擇啟動模式;
- 給SP、PC指針賦值;
- 進(jìn)入復(fù)位中斷程序;
- 進(jìn)入main函數(shù)。
三、各個過程深入分析
1.?由boot引腳選擇啟動模式
stm32復(fù)位(上電復(fù)位、硬件復(fù)位、軟件復(fù)位),會將復(fù)位后的起始地址和中斷向量表重映射到其他地址,具體映射到哪個地址由boot0和boot1決定。具體映射關(guān)系如下圖所示。
啟動模式對應(yīng)映射地址
其中最常用的啟動模式就是映射到內(nèi)部FLASH啟動,這也是接下來重點介紹的模式。
映射到內(nèi)部SRAM啟動的使用場景比較少,代碼在SRAM的執(zhí)行速度較快,可運用在一些調(diào)試需頻繁更新代碼的場合。
映射到系統(tǒng)存儲器一般是用于bootloader引導(dǎo)程序升級時使用,在程序本地升級和OTA升級時都會用。
2.?給SP、PC指針賦值
選擇內(nèi)部FLASH啟動后,程序會將棧指針SP指向0x08000000,這個地址保存的是__initial_sp的地址,也就是程序棧頂?shù)刂?,還會將程序計數(shù)器指針指向0x08000004,這個地址保存的是Reset_Handler的地址,這里結(jié)合具體的啟動文件,map文件和hex文件來證實這一點。
啟動文件的中斷向量表
map文件和hex文件對比
這里從map文件中選取__initial_sp和Reset_Handler的地址與hex文件中最開始執(zhí)行的指令比較,發(fā)現(xiàn)兩者相等,即證明了程序的執(zhí)行確實如上所述。這里有兩個需要注意的點,stm32是小端模式,因此hex文件中的指令是按照字節(jié)的高位在地址高位,字節(jié)的低位在地址低位的規(guī)則。Reset_Handler的地址最后一位為啥是1,stm32的指令不都是16位和32位的嘛,其實這里涉及到指令集的問題,ARM cortexM3執(zhí)行的是Thumb-2指令集,同時兼容16位的ARM指令和32位的Thumb的指令,為了區(qū)分兩個指令集,規(guī)定指令最低位為1就是Thumb指令,為0就是ARM指令。
初始化SP、PC指針的示意圖
3. 進(jìn)入復(fù)位中斷程序
上一步中PC指針指向了Reset_Handler函數(shù),這也是程序復(fù)位后執(zhí)行的第一條指令。
可以看到在Reset_Handler函數(shù)里主要執(zhí)行了 SystemInit 和 __main 這兩個函數(shù),其中SystemInit函數(shù)是庫函數(shù),它的主要作用是初始化系統(tǒng)時鐘(通過調(diào)用SetSysClock)。
__main 函數(shù)是標(biāo)準(zhǔn)的C庫函數(shù),當(dāng)編譯器發(fā)現(xiàn)了主程序中有main函數(shù),就會自動創(chuàng)建__main函數(shù)。它的主要作用是初始化RW段和ZI段(通過調(diào)用__scatterload),初始化堆棧以及跳轉(zhuǎn)到主程序的main函數(shù)(通過調(diào)用__rt_entry)。
4. 進(jìn)入main函數(shù)
執(zhí)行main函數(shù)中的while死循環(huán),當(dāng)中斷到來時從中斷向量表中找到對應(yīng)的中斷服務(wù)函數(shù)并執(zhí)行。
#通信硬件知識分享#