RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

一文詳解STM32單片機(jī)的啟動(dòng)文件

開源嵌入式 ? 來源:開源嵌入式 ? 作者:富貴人 ? 2022-04-26 14:32 ? 次閱讀

一、概述

1、說明

每一款芯片的啟動(dòng)文件都值得去研究,因?yàn)樗墒悄愕某绦蚺艿淖畛跻欢温?,不可以不知道。通過了解啟動(dòng)文件,我們可以體會到處理器的架構(gòu)、指令集、中斷向量安排等內(nèi)容,是非常值得玩味的。

STM32作為一款高端Cortex-M3系列單片機(jī),有必要了解它的啟動(dòng)文件。打好基礎(chǔ),為以后優(yōu)化程序,寫出高質(zhì)量的代碼最準(zhǔn)備。

2、整體過程概括

STM整個(gè)啟動(dòng)過程是指從上電開始,一直到運(yùn)行到main函數(shù)之間的這段過程,步驟為(以使用微庫為例):

①上電后硬件設(shè)置SP、PC

②設(shè)置系統(tǒng)時(shí)鐘

③軟件設(shè)置SP

④加載.data、.bss,并初始化棧區(qū)

⑤跳轉(zhuǎn)到C文件的main函數(shù)

3、整個(gè)啟動(dòng)過程涉及的代碼

啟動(dòng)過程涉及的文件不僅包含startup_stm32f10x_hd.s,還涉及到了MDK自帶的連接庫文件entry.o、entry2.o、entry5.o、entry7.o等(從生成的map文件可以看出來)。

二、程序在Flash上的存儲結(jié)構(gòu)

在真正講解啟動(dòng)過程之前,先要講解程序下載到Flash上的結(jié)構(gòu)和程序運(yùn)行時(shí)(執(zhí)行到main函數(shù))時(shí)的SRAM數(shù)據(jù)結(jié)構(gòu)。程序在用戶Flash上的結(jié)構(gòu)如下圖所示。下圖是通過閱讀hex文件和在MDK下調(diào)試綜合提煉出來的。

151a4786-c2ac-11ec-bce3-dac502259ad0.jpg

MSP初始值編譯器生成,主堆棧的初始值

異常向量表不多說

外部中斷向量表不多說

代碼段存放代碼

初始化數(shù)據(jù)段.data

未初始化數(shù)據(jù)段.bss

加載數(shù)據(jù)段和初始化棧的參數(shù)

加載數(shù)據(jù)段和初始化棧的參數(shù)分別有4個(gè),這里只講解加載數(shù)據(jù)段的參數(shù),至于初始化棧的參數(shù)類似。

0x0800 033cFlash上的數(shù)據(jù)段(初始化數(shù)據(jù)段和未初始化數(shù)據(jù)段)起始地址

0x2000 0000加載到SRAM上的目的地址

0x0000 000c數(shù)據(jù)段的總大小

0x0800 02f4調(diào)用函數(shù)_scatterload_copy

需要說明的是初始化棧的函數(shù)--0x0800 0304與加載數(shù)據(jù)段的函數(shù)不一樣,為_scatterload_zeroinit,它的目的就是將??臻g清零。

152cfdae-c2ac-11ec-bce3-dac502259ad0.png

三、數(shù)據(jù)在SRAM上的結(jié)構(gòu)

程序運(yùn)行時(shí)(執(zhí)行到main函數(shù))時(shí)的SRAM數(shù)據(jù)結(jié)構(gòu)

153f4388-c2ac-11ec-bce3-dac502259ad0.png

四、詳細(xì)過程分析

有了以上的基礎(chǔ),現(xiàn)在詳細(xì)分析啟動(dòng)過程。

1、上電后硬件設(shè)置SP、PC

剛上電復(fù)位后,硬件會自動(dòng)根據(jù)向量表偏移地址找到向量表,向量表偏移地址的定義如下:

1552b198-c2ac-11ec-bce3-dac502259ad0.png

調(diào)試現(xiàn)象如下:

156feed4-c2ac-11ec-bce3-dac502259ad0.png

看看我們的向量表內(nèi)容(通過J-Flash打開hex文件)

15834344-c2ac-11ec-bce3-dac502259ad0.png

硬件這時(shí)自動(dòng)從0x0800 0000位置處讀取數(shù)據(jù)賦給棧指針SP,然后自動(dòng)從0x0800 0004位置處讀取數(shù)據(jù)賦給PC,完成復(fù)位,結(jié)果為:

SP = 0x0200 0810

PC = 0x0800 0145

2、設(shè)置系統(tǒng)時(shí)鐘

15923214-c2ac-11ec-bce3-dac502259ad0.png

上一步中令PC=0x0800 0145的地址沒有對齊,硬件自動(dòng)對齊到0x0800 0144,執(zhí)行SystemInit函數(shù)初始化系統(tǒng)時(shí)鐘。

3、軟件設(shè)置SP

LDR   R0,=__main
BX R0

執(zhí)行上兩條之類,跳轉(zhuǎn)到__main程序段運(yùn)行,注意不是main函數(shù),___main的地址是0x0800 0130。

15a559e8-c2ac-11ec-bce3-dac502259ad0.png

可以看到指令LDR.W sp,[pc,#12],結(jié)果SP=0x2000 0810。

4、加載.data、.bss,并初始化棧區(qū)

BL.W     __scatterload_rt2

進(jìn)入__scatterload_rt2代碼段。

__scatterload_rt2:0x08000168 4C06      LDR      r4,[pc,#24]  ; 
@0x080001840x0800016A 4D07   LDR  r5,[pc,#28]  ; 
@0x080001880x0800016C E006    B   0x0800017C0x0800016E 68E0 LDR      
r0,[r4,#0x0C]0x08000170 F0400301  ORR      
r3,r0,#0x010x08000174 E8940007  LDM  r4,{r0-r2}0x08000178 4798   
BLX r30x0800017A 3410  ADDS  r4,r4,#0x100x0800017C 42AC   
CMP r4,r50x0800017E D3F6  BCC 0x0800016E0x08000180 F7FFFFDA  
BL.W   _main_init (0x08000138)

這段代碼是個(gè)循環(huán)(BCC 0x0800016e),實(shí)際運(yùn)行時(shí)候循環(huán)了兩次。第一次運(yùn)行的時(shí)候,讀取“加載數(shù)據(jù)段的函數(shù)(_scatterload_copy)”的地址并跳轉(zhuǎn)到該函數(shù)處運(yùn)行(注意加載已初始化數(shù)據(jù)段和未初始化數(shù)據(jù)段用的是同一個(gè)函數(shù));第二次運(yùn)行的時(shí)候,讀取“初始化棧的函數(shù)(_scatterload_zeroinit)”的地址并跳轉(zhuǎn)到該函數(shù)處運(yùn)行。相應(yīng)的代碼如下:

0x0800016E 68E0      LDR      r0,[r4,#0x0C]
0x08000170 F0400301  ORR      r3,r0,#0x01
0x08000174  
0x08000178 4798      BLX      r3
當(dāng)然執(zhí)行這兩個(gè)函數(shù)的時(shí)候,還需要傳入?yún)?shù)。
至于參數(shù),我們在“加載數(shù)據(jù)段和初始化棧的參數(shù)”環(huán)節(jié)已經(jīng)闡述過了。
當(dāng)這兩個(gè)函數(shù)都執(zhí)行完后,結(jié)果就是“數(shù)據(jù)在SRAM上的結(jié)構(gòu)”所展示的圖。
最后,也把事實(shí)加載和初始化的兩個(gè)函數(shù)代碼奉上如下:
5、跳轉(zhuǎn)到C文件的main函數(shù)
_main_init:0x08000138 4800      LDR      r0,[pc,#0]  ;
@0x0800013C0x0800013A 4700      BX       r0

五、異常向量與中斷向量表

; Vector Table Mapped to Address 0 at Reset
        AREA  RESET, DATA, READONLY
        EXPORT __Vectors
        EXPORT __Vectors_End
        EXPORT __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   0             ; Reserved
        DCD   0             ; Reserved
        DCD   0             ; Reserved
        DCD   SVC_Handler        ; SVCall Handler
        DCD   DebugMon_Handler      ; Debug Monitor Handler
        DCD   0             ; Reserved
        DCD   PendSV_Handler       ; PendSV Handler
        DCD   SysTick_Handler      ; SysTick Handler
        ; External Interrupts
        DCD   WWDG_IRQHandler      ; Window Watchdog
        DCD   PVD_IRQHandler       ; PVD through EXTI Line
        DCD   TAMPER_IRQHandler     ; Tamper
        DCD   RTC_IRQHandler       ; RTC
        DCD   FLASH_IRQHandler      ; Flash
        DCD   RCC_IRQHandler       ; RCC
        DCD   EXTI0_IRQHandler      ; EXTI Line 0
        DCD   EXTI1_IRQHandler      ; EXTI Line 1
        DCD   EXTI2_IRQHandler      ; EXTI Line 2
        DCD   EXTI3_IRQHandler      ; EXTI Line 3
        DCD   EXTI4_IRQHandler      ; EXTI Line 4
        DCD   DMA1_Channel1_IRQHandler  ; DMA1 Channel 1
        DCD   DMA1_Channel2_IRQHandler  ; DMA1 Channel 2
        DCD   DMA1_Channel3_IRQHandler  ; DMA1 Channel 3
        DCD   DMA1_Channel4_IRQHandler  ; DMA1 Channel 4
        DCD   DMA1_Channel5_IRQHandler  ; DMA1 Channel 5
        DCD   DMA1_Channel6_IRQHandler  ; DMA1 Channel 6
        DCD   DMA1_Channel7_IRQHandler  ; DMA1 Channel 7
        DCD   ADC1_2_IRQHandler     ; ADC1 & ADC2
        DCD   USB_HP_CAN1_TX_IRQHandler ; USB High Priority or CAN1 TX
        DCD   USB_LP_CAN1_RX0_IRQHandler ; USB Low Priority or CAN1 RX0
        DCD   CAN1_RX1_IRQHandler    ; CAN1 RX1
        DCD   CAN1_SCE_IRQHandler    ; CAN1 SCE
        DCD   EXTI9_5_IRQHandler     ; EXTI Line 9..5
        DCD   TIM1_BRK_IRQHandler    ; TIM1 Break
        DCD   TIM1_UP_IRQHandler     ; TIM1 Update
        DCD   TIM1_TRG_COM_IRQHandler  ; TIM1 Trigger and Commutation
        DCD   TIM1_CC_IRQHandler     ; TIM1 Capture Compare
        DCD   TIM2_IRQHandler      ; TIM2
        DCD   TIM3_IRQHandler      ; TIM3
        DCD   TIM4_IRQHandler      ; TIM4
        DCD   I2C1_EV_IRQHandler     ; I2C1 Event
        DCD   I2C1_ER_IRQHandler     ; I2C1 Error
        DCD   I2C2_EV_IRQHandler     ; I2C2 Event
        DCD   I2C2_ER_IRQHandler     ; I2C2 Error
        DCD   SPI1_IRQHandler      ; SPI1
        DCD   SPI2_IRQHandler      ; SPI2
        DCD   USART1_IRQHandler     ; USART1
        DCD   USART2_IRQHandler     ; USART2
        DCD   USART3_IRQHandler     ; USART3
        DCD   EXTI15_10_IRQHandler    ; EXTI Line 15..10
        DCD   RTCAlarm_IRQHandler    ; RTC Alarm through EXTI Line
        DCD   USBWakeUp_IRQHandler    ; USB Wakeup from suspend
        DCD   TIM8_BRK_IRQHandler    ; TIM8 Break
        DCD   TIM8_UP_IRQHandler     ; TIM8 Update
        DCD   TIM8_TRG_COM_IRQHandler  ; TIM8 Trigger and Commutation
        DCD   TIM8_CC_IRQHandler     ; TIM8 Capture Compare
        DCD   ADC3_IRQHandler      ; ADC3
        DCD   FSMC_IRQHandler      ; FSMC
        DCD   SDIO_IRQHandler      ; SDIO
        DCD   TIM5_IRQHandler      ; TIM5
        DCD   SPI3_IRQHandler      ; SPI3
        DCD   UART4_IRQHandler      ; UART4
        DCD   UART5_IRQHandler      ; UART5
        DCD   TIM6_IRQHandler      ; TIM6
        DCD   TIM7_IRQHandler      ; TIM7
        DCD   DMA2_Channel1_IRQHandler  ; DMA2 Channel1
        DCD   DMA2_Channel2_IRQHandler  ; DMA2 Channel2
        DCD   DMA2_Channel3_IRQHandler  ; DMA2 Channel3
        DCD   DMA2_Channel4_5_IRQHandler ; DMA2 Channel4 & Channel5
__Vectors_End
這段代碼就是定義異常向量表,在之前有一個(gè)“J-Flash打開hex文件”的圖片跟這個(gè)表格是一一對應(yīng)的。編譯器根據(jù)我們定義的函數(shù) Reset_Handler、NMI_Handler等,在連接程序階段將這個(gè)向量表填入這些函數(shù)的地址。
startup_stm32f10x_hd.s內(nèi)容:
NMI_Handler   PROC
         EXPORT  NMI_Handler         [WEAK]
         B    .
         ENDP
stm32f10x_it.c中內(nèi)容:void NMI_Handler(void)
{
}

在啟動(dòng)匯編文件中已經(jīng)定義了函數(shù)NMI_Handler,但是使用了“弱”,它允許我們再重新定義一個(gè)NMI_Handler函數(shù),程序在編譯的時(shí)候會將匯編文件中的弱函數(shù)“覆蓋掉”--兩個(gè)函數(shù)的代碼在連接后都存在,只是在中斷向量表中的地址填入的是我們重新定義函數(shù)的地址。

六、使用微庫與不使用微庫的區(qū)別

15b89ad0-c2ac-11ec-bce3-dac502259ad0.png

使用微庫就意味著我們不想使用MDK提供的庫函數(shù),而想用自己定義的庫函數(shù),比如說printf函數(shù)。那么這一點(diǎn)是怎樣實(shí)現(xiàn)的呢?我們以printf函數(shù)為例進(jìn)行說明。

1、不使用微庫而使用系統(tǒng)庫

在連接程序時(shí),肯定會把系統(tǒng)中包含printf函數(shù)的庫拿來調(diào)用參與連接,即代碼段有系統(tǒng)庫的參與。

在啟動(dòng)過程中,不使用微庫而使用系統(tǒng)庫在初始化棧的時(shí)候,還需要初始化堆(猜測系統(tǒng)庫需要用到堆),而使用微庫則是不需要的。

IF __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

另外,在執(zhí)行__main函數(shù)的過程中,不僅需要完成“使用微庫”情況下的所有工作,額外的工作還需要進(jìn)行庫的初始化,才能使用系統(tǒng)庫(這一部分我還沒有深入探討)。附上__main函數(shù)的內(nèi)容:

__main:0x08000130 F000F802  BL.W     
__scatterload_rt2_thumb_only (0x08000138)   
__rt_entry_sh (0x080001B0)
__scatterload_rt2_thumb_only:0x08000138 A00A  
__scatterload_null:0x08000146 45DA   CMP   
__scatterload_copy:0x0800016C 3A10      SUBS    
__scatterload_zeroinit:0x08000188 2300  0001A2 
__rt_lib_init:0x080001A4 B51F      PUSH       
__rt_lib_init_user_alloc_1:0x080001AA BD1F      
__rt_lib_shutdown:0x080001AC B510   PUSH  
__rt_lib_shutdown_user_alloc_1:0x080001AE BD10   
__rt_entry_sh:0x080001B0 F000F82F  BL.W
__rt_entry_postsh_1:0x080001B6 F7FFFFF5  BL.W     
__rt_entry_postli_1:0x080001BA F000F919  BL.W

2、使用微庫而不使用系統(tǒng)庫

在程序連接時(shí),不會把包含printf函數(shù)的庫連接到終極目標(biāo)文件中,而使用我們定義的庫。啟動(dòng)時(shí)需要完成的工作就是之前論述的步驟1、2、3、4、5,相比使用系統(tǒng)庫,啟動(dòng)過程步驟更少。

原文標(biāo)題:【編程高手都必備】STM32F1x系列精髓啟動(dòng)過程與啟動(dòng)文件分析

文章出處:【微信公眾號:開源嵌入式】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

審核編輯:湯梓紅
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 單片機(jī)
    +關(guān)注

    關(guān)注

    6034

    文章

    44552

    瀏覽量

    634467
  • STM32
    +關(guān)注

    關(guān)注

    2270

    文章

    10893

    瀏覽量

    355683
  • 啟動(dòng)文件
    +關(guān)注

    關(guān)注

    0

    文章

    15

    瀏覽量

    2222

原文標(biāo)題:【編程高手都必備】STM32F1x系列精髓啟動(dòng)過程與啟動(dòng)文件分析

文章出處:【微信號:KY_QRS,微信公眾號:開源嵌入式】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    STM32單片機(jī)啟動(dòng)文件及FLASH分配

    STM32作為單片機(jī),它的啟動(dòng)方式很簡單,即當(dāng)Boot配置了從內(nèi)部Flash啟動(dòng)模式之后,
    發(fā)表于 01-11 17:24 ?4644次閱讀
    <b class='flag-5'>STM32</b><b class='flag-5'>單片機(jī)</b>的<b class='flag-5'>啟動(dòng)</b><b class='flag-5'>文件</b>及FLASH分配

    淺析STM32單片機(jī)啟動(dòng)文件

    今天來總結(jié)的stm32基礎(chǔ)知識是啟動(dòng)文件相關(guān)。要想對是stm32單片機(jī)有個(gè)深入的理解,那么啟動(dòng)
    發(fā)表于 06-12 16:49 ?2026次閱讀
    淺析<b class='flag-5'>STM32</b><b class='flag-5'>單片機(jī)</b>的<b class='flag-5'>啟動(dòng)</b><b class='flag-5'>文件</b>

    什么是單片機(jī)STM32啟動(dòng)文件?

    什么是單片機(jī)STM32啟動(dòng)文件?
    發(fā)表于 11-04 07:46

    單片機(jī)啟動(dòng)文件

    需要的資源有stm32f10x開發(fā)板stm32參考手冊首先我們來了解一下單片機(jī)啟動(dòng)
    發(fā)表于 01-05 07:31

    詳解MCS-51單片機(jī)的中斷系統(tǒng)

    詳解MCS-51單片機(jī)的中斷系統(tǒng),具體的跟隨小編來了解下。
    的頭像 發(fā)表于 07-28 11:26 ?1.3w次閱讀
    <b class='flag-5'>一</b><b class='flag-5'>文</b><b class='flag-5'>詳解</b>MCS-51<b class='flag-5'>單片機(jī)</b>的中斷系統(tǒng)

    STM32啟動(dòng)文件內(nèi)容詳解

    前言使用STM32單片機(jī)時(shí)候,必須導(dǎo)入對應(yīng)型號的啟動(dòng)文件。這個(gè)筆記在于對于啟動(dòng)文件的內(nèi)容的分析,
    發(fā)表于 11-30 13:21 ?8次下載
    <b class='flag-5'>STM32</b><b class='flag-5'>啟動(dòng)</b><b class='flag-5'>文件</b>內(nèi)容<b class='flag-5'>詳解</b>

    STM32單片機(jī)中Hex、Bin文件的區(qū)別及應(yīng)用詳解

    ? ? STM32、51等單片機(jī)程序經(jīng)過編譯后,生成的hex文件、bin文件,它們都是單片機(jī)燒寫文件
    的頭像 發(fā)表于 07-05 17:23 ?1.3w次閱讀

    基于STM32單片機(jī)ADC使用庫文件設(shè)計(jì)源代碼

    基于STM32單片機(jī)ADC使用庫文件設(shè)計(jì)源代碼
    發(fā)表于 04-26 15:07 ?6次下載

    基于STM32單片機(jī)DMA使用庫文件設(shè)計(jì)源代碼

    基于STM32單片機(jī)DMA使用庫文件設(shè)計(jì)源代碼)
    發(fā)表于 04-26 15:03 ?2次下載

    基于STM32單片機(jī)OLED顯示使用庫文件設(shè)計(jì)源代碼

    基于STM32單片機(jī)OLED顯示使用庫文件設(shè)計(jì)源代碼
    發(fā)表于 04-26 14:59 ?3次下載

    基于STM32單片機(jī)SD卡使用庫文件設(shè)計(jì)源代碼

    基于STM32單片機(jī)SD卡使用庫文件設(shè)計(jì)源代碼
    發(fā)表于 04-26 14:27 ?2次下載

    基于STM32單片機(jī)SPI使用庫文件設(shè)計(jì)源代碼

    基于STM32單片機(jī)SPI使用庫文件設(shè)計(jì)源代碼
    發(fā)表于 04-26 14:26 ?5次下載

    基于STM32單片機(jī)TFTLCD顯示使用庫文件設(shè)計(jì)源代碼

    基于STM32單片機(jī)TFTLCD顯示使用庫文件設(shè)計(jì)源代碼
    發(fā)表于 04-26 14:54 ?1次下載

    基于STM32單片機(jī)按鍵輸入使用庫文件設(shè)計(jì)源代碼

    基于STM32單片機(jī)按鍵輸入使用庫文件設(shè)計(jì)源代碼
    發(fā)表于 04-26 14:53 ?0次下載

    詳解GD32單片機(jī)STM32單片機(jī)

    GD32單片機(jī)是中國龍芯集成電路公司推出的款A(yù)RM Cortex-M3內(nèi)核的微控制器。它具有與STM32單片機(jī)相同的架構(gòu)和指令集,但是價(jià)格相比ST
    發(fā)表于 08-09 16:58 ?1.1w次閱讀
    RM新时代网站-首页