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

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

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

從上電到啟動(dòng),帶你拿捏單片機(jī)啟動(dòng)全流程

朱老師物聯(lián)網(wǎng)大講堂 ? 2024-05-07 08:10 ? 次閱讀


從事嵌入式開(kāi)發(fā)的伙伴可能會(huì)思考過(guò)一個(gè)問(wèn)題,我們一般都是使用芯片廠商提供的驅(qū)動(dòng)庫(kù)和初始化文件,直接從main函數(shù)開(kāi)始寫(xiě)程序,那么系統(tǒng)上電之后,程序怎么引導(dǎo)進(jìn)main函數(shù)執(zhí)行的呢?還有,系統(tǒng)上電之后RAM的數(shù)據(jù)是隨機(jī)的,那么定義的全局變量的初始值又是怎么實(shí)現(xiàn)的呢?下面我將帶著這兩個(gè)問(wèn)題,以Cortex-M架構(gòu)為例,采用IAR EWARM作為編譯工具鏈,從系統(tǒng)上電之后執(zhí)行的第一條代碼開(kāi)始,梳理系統(tǒng)的啟動(dòng)過(guò)程,了解編譯器在此期間所做的工作。其他的工具鏈,如Keil和GCC在系統(tǒng)初始化過(guò)程所做的工作也是相似的,但具體的實(shí)現(xiàn)有所差異。

一、啟動(dòng)文件

芯片廠商提供的啟動(dòng)文件,一般是采用匯編語(yǔ)言編寫(xiě),少數(shù)用C語(yǔ)言。在啟動(dòng)文件中一般至少存在下面兩個(gè)部分內(nèi)容:向量表默認(rèn)的中斷和異常處理程序

向量表實(shí)際上是一個(gè)數(shù)組,放置在存儲(chǔ)器的零地址,每個(gè)元素存儲(chǔ)的是各個(gè)中斷或異常處理程序的入口地址。以STM32F107芯片基于IAR工具的啟動(dòng)文件為例:

33a54eb2-0c06-11ef-9118-92fbcf53809c.png

文件的開(kāi)頭定義了一個(gè)名為_(kāi)_vector_table的全局符號(hào),“DATA”的作用是在代碼段中定義一個(gè)數(shù)據(jù)區(qū),用作向量表。數(shù)據(jù)區(qū)的內(nèi)容是使用DCD指令定義的32位寬度常量,除了第一個(gè)sfe(CSTACK)比較特殊以為,其他的常量都是異常和中斷服務(wù)程序的地址(在編譯時(shí)函數(shù)名會(huì)被替換成函數(shù)的入口地址)。sfe(CSTACK)是IAR匯編器段操作,用于獲取段(section)的結(jié)束地址,在這里意欲何為呢?實(shí)際上這是獲取堆棧基地址的操作。IAR在鏈接器腳本(*.icf)文件中定義堆棧,實(shí)際是定義了一個(gè)名為“CSTACK”的空閑塊(block),如下圖的腳本命令所示。所謂的塊就是保留一段連續(xù)的地址空間,用來(lái)作為堆?;蛘叨?。當(dāng)然,塊也可以是用內(nèi)容的,例如可以用來(lái)管理段,但不在今天的討論范圍。33bb593c-0c06-11ef-9118-92fbcf53809c.png我們知道Cortex-M架構(gòu)的堆棧模型是滿減棧,堆棧從高地址向低地址增長(zhǎng),因此堆棧的基地址是CSTACK的結(jié)束地址。向量表的第一個(gè)元素是?;愤@是由Cortex-M架構(gòu)定義的。系統(tǒng)上電后硬件自動(dòng)從向量表中獲取,并設(shè)置主堆棧指針MSP,而不是像其他ARM架構(gòu),堆棧指針需要通過(guò)軟件來(lái)設(shè)置。向量表中第二個(gè)元素是復(fù)位異常(Reset_Handler)的入口地址。系統(tǒng)上電后,硬件自動(dòng)從__vector_table + 4的位置讀取,并從讀取到的地址開(kāi)始執(zhí)行。系統(tǒng)上電后CPU執(zhí)行的第一條是Reset_Handler函數(shù)的第一條語(yǔ)句。33c8f0d8-0c06-11ef-9118-92fbcf53809c.png

上面的THUMB命令表示接下來(lái)的代碼采用THUMB模式(Cortex-M只支持Thumb-2指令集);SECTION用于定義一個(gè)段,段名為“.ResetHandler”,段的類型是代碼(CODE);REODER指示用給定的名稱開(kāi)啟一個(gè)新的段;ROOT指示鏈接器,當(dāng)段內(nèi)的符號(hào)沒(méi)有被引用,鏈接器也不可以丟棄這個(gè)段。

PUBWEAK是弱定義,如果用戶在其他位置編寫(xiě)了中斷處理函數(shù),在連接時(shí)實(shí)際鏈接用戶所編寫(xiě)的,啟動(dòng)文件中用匯編寫(xiě)的服務(wù)函數(shù)會(huì)忽略。之所以要在啟動(dòng)文件中以弱定義的方式編寫(xiě)全部的異常和中斷服務(wù)函數(shù),是為了防止用戶在沒(méi)有編寫(xiě)服務(wù)函數(shù)的情況下開(kāi)啟并觸發(fā)了中斷,導(dǎo)致系統(tǒng)的不確定。

二、系統(tǒng)初始化過(guò)程

在EWARM的工程O(píng)ptions > Debugger > Setup中將“Run to”勾選取消,這樣在進(jìn)入調(diào)試之后就會(huì)停第一條要執(zhí)行的代碼的位置:

341a0b6c-0c06-11ef-9118-92fbcf53809c.png

進(jìn)入調(diào)試之后會(huì)停在啟動(dòng)文件Reset_Handler函數(shù)第一條匯編指令位置:

34286dc4-0c06-11ef-9118-92fbcf53809c.png

此時(shí),通過(guò)寄存器觀察窗口查看SP的值為0x20009820。通過(guò)鏈接時(shí)生成的map文件,查看CSTACK的地址范圍,0x20009820正好是CSTACK的結(jié)束地址。有了MSP,C代碼就能運(yùn)行了。

34329664-0c06-11ef-9118-92fbcf53809c.png

ystemInit函數(shù)是芯片廠商根據(jù)ARM的CMSIS標(biāo)準(zhǔn)提供的一個(gè)系統(tǒng)基礎(chǔ)配置函數(shù),配置基礎(chǔ)的時(shí)鐘系統(tǒng)和向量表重定位等。這里的LDR是偽指令,它將SystemInit函數(shù)的地址加載到寄存器R0,實(shí)際上是通過(guò)PC偏移尋址來(lái)獲取SystemInit的地址。

34426850-0c06-11ef-9118-92fbcf53809c.png3450cecc-0c06-11ef-9118-92fbcf53809c.png

從上面的圖可以發(fā)現(xiàn)一個(gè)問(wèn)題,在反匯編窗口可以觀察到SystemInit的地址是0x20000150,但加載到R0寄存器后卻是0x20000151。這是因?yàn)樵谑褂锰D(zhuǎn)指令更新PC時(shí),需要置PC的LSB為1,以表示THUMB模式,由于Cortex-M不支持ARM模式,因此LSB總是1。

執(zhí)行完芯片廠商提供的SystemInit函數(shù)之后,跳轉(zhuǎn)到__iar_program_start,這是IAR編譯器提供的初始化代碼的入口。

34719882-0c06-11ef-9118-92fbcf53809c.png

__iar_program_start首先會(huì)執(zhí)行兩個(gè)函數(shù):__iar_init_core和__iar_init_vfp,可以完成一些CPU和FPU相關(guān)的初始化操作,在某些ARM架構(gòu)打包好的運(yùn)行時(shí)庫(kù)會(huì)有這兩個(gè)函數(shù),用戶也可以重寫(xiě)這兩個(gè)函數(shù)來(lái)自己實(shí)現(xiàn)一些相關(guān)的操作。

之后,跳轉(zhuǎn)到__cmain函數(shù)執(zhí)行。在__cmain中調(diào)用了一個(gè)__low_level_init函數(shù),該函數(shù)專門(mén)用于提供給用戶編寫(xiě)一個(gè)初階的初始化操作,它在全局變量初始化之前執(zhí)行,例如可用在__low_level_init中初始化SDRAM,這樣就可以將全局變量定義到SDRAM中使用。

347c34d6-0c06-11ef-9118-92fbcf53809c.png

__low_level_init可以在任意的C文件中編寫(xiě),注意它的返回值,如果返回0,后續(xù)就會(huì)跳過(guò)變量初始化操作,正常一般都是返回1。

348992de-0c06-11ef-9118-92fbcf53809c.png

三、全局變量的初始化

此后進(jìn)入到__iar_data_init3函數(shù),在這里會(huì)完成所有具有初始值的全局/靜態(tài)變量的賦值,以及零初始化全局/靜態(tài)變量的清零操作,分別調(diào)用__iar_copy_init3和__iar_zero_init3,將保存在ROM區(qū)由鏈接器生成的變量初始值復(fù)制到變量的地址。注意,新的EWARM版本默認(rèn)變量初始化操作可能會(huì)采用壓縮算法,實(shí)際變量初始化調(diào)用的函數(shù)可能有區(qū)別。34b4b3ec-0c06-11ef-9118-92fbcf53809c.png

在全局變量未初始化之前,通過(guò)watch窗口可以看到,變量的值都是隨機(jī)數(shù)。

34c207c2-0c06-11ef-9118-92fbcf53809c.png

在__iar_data_init3執(zhí)行完成后,全部變量的初值賦值已經(jīng)完成。

34cd1270-0c06-11ef-9118-92fbcf53809c.png

在__cmain函數(shù)的最后,跳轉(zhuǎn)到用戶的main函數(shù),最終開(kāi)始用戶的代碼執(zhí)行。

34dc4286-0c06-11ef-9118-92fbcf53809c.png

四、總結(jié)

339b54ca-0c06-11ef-9118-92fbcf53809c.png

了解了編譯器所提供的初始化過(guò)程和處理器架構(gòu),我們可以根據(jù)自己的需求定制系統(tǒng)的初始化。例如,在進(jìn)入__iar_program_start之前,就可以執(zhí)行必要的硬件初始化操作,可以用匯編寫(xiě),也可以用C寫(xiě)。還可以手動(dòng)控制變量的初始化操作,自己實(shí)現(xiàn)變量的初始化。甚至,完全不采用IAR編譯器提供的初始化操作,自己從復(fù)位序列引導(dǎo)至main函數(shù)那也是可以的。

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

    關(guān)注

    450

    文章

    49636

    瀏覽量

    417148
  • 單片機(jī)
    +關(guān)注

    關(guān)注

    6023

    文章

    44376

    瀏覽量

    628363
  • 嵌入式
    +關(guān)注

    關(guān)注

    5046

    文章

    18817

    瀏覽量

    298515
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    單片機(jī)復(fù)位和冷啟動(dòng)詳細(xì)介紹

    單片機(jī)啟動(dòng)很簡(jiǎn)單,關(guān),再上,正常復(fù)位后,就冷啟動(dòng)成功。單片機(jī)
    的頭像 發(fā)表于 02-12 13:38 ?2w次閱讀
    <b class='flag-5'>單片機(jī)</b>復(fù)位和冷<b class='flag-5'>啟動(dòng)</b>詳細(xì)介紹

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

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

    單片機(jī)啟動(dòng)代碼

    帶你來(lái)看看單片機(jī)啟動(dòng)代碼!
    發(fā)表于 05-26 12:45

    單片機(jī)有時(shí)候上啟動(dòng)是為什么

    遇到有些國(guó)產(chǎn) 單片機(jī)有時(shí)候上啟動(dòng)的問(wèn)題,一般出現(xiàn)的情況是LVR設(shè)置有問(wèn)題,最常見(jiàn)是兼容3.3V 5V供電的MCU,有時(shí)候默認(rèn)是5V配置,在3.3V可能出現(xiàn)上無(wú)法
    發(fā)表于 11-03 06:11

    單片機(jī)是如何啟動(dòng)

    接觸單片機(jī)有幾年的時(shí)間了,一直專注于如何在單片機(jī)上寫(xiě)一些應(yīng)用,對(duì)單片機(jī)如何啟動(dòng)的知之甚少,慚愧慚愧。。。今天得空整理了一下,加深了對(duì)單片機(jī)
    發(fā)表于 11-03 08:58

    單片機(jī)是如何啟動(dòng)

    單片機(jī)啟動(dòng)過(guò)程是加后,先運(yùn)行芯片內(nèi)部固有程序(這個(gè)程序是用戶訪問(wèn)不到也改寫(xiě)不了的),即啟動(dòng)代碼。啟動(dòng)代碼程序建立完運(yùn)行環(huán)境后,會(huì)去讀串口
    發(fā)表于 11-25 09:26

    RK3188 從上開(kāi)始啟動(dòng)內(nèi)核為止的過(guò)程是怎樣去完成的

    如何獲取RK3066的BootRom呢?有哪些步驟?RK3188從上開(kāi)始啟動(dòng)內(nèi)核為止的過(guò)程是怎樣去完成的?
    發(fā)表于 02-18 07:11

    單片機(jī)啟動(dòng)代碼詳細(xì)資料說(shuō)明

    對(duì)于熟悉電腦的伙伴們來(lái)說(shuō),BIOS(那個(gè)藍(lán)色的界面)可能不會(huì)太陌生吧,這貨就是電腦的啟動(dòng)代碼。沒(méi)有BIOS的電腦,那注定是一塊板磚!BIOS主要是做一些開(kāi)機(jī)前的準(zhǔn)備工作,例如系統(tǒng)時(shí)間設(shè)定、啟動(dòng)順序。。。扯遠(yuǎn)了!其實(shí)電腦本身就是從單片機(jī)
    發(fā)表于 07-29 17:36 ?0次下載
    <b class='flag-5'>單片機(jī)</b>的<b class='flag-5'>啟動(dòng)</b>代碼詳細(xì)資料說(shuō)明

    單片機(jī)啟動(dòng)代碼

    。。。扯遠(yuǎn)了!其實(shí)電腦本身就是從單片機(jī)而來(lái),那么單片機(jī)也是有啟動(dòng)代碼的,只是我們絕大部分情況不去關(guān)心它。啟動(dòng)代碼究竟都干了些什么工作,為何需要它?想想你在c語(yǔ)言中用到了什么東西,而這些
    發(fā)表于 11-13 16:06 ?30次下載
    <b class='flag-5'>單片機(jī)</b>的<b class='flag-5'>啟動(dòng)</b>代碼

    單片機(jī)啟動(dòng)過(guò)程

    啟動(dòng)過(guò)程簡(jiǎn)介單片機(jī)啟動(dòng)過(guò)程是加后,先運(yùn)行芯片內(nèi)部固有程序(這個(gè)程序是用戶訪問(wèn)不到也改寫(xiě)不了的),即啟動(dòng)代碼。
    發(fā)表于 11-17 10:21 ?8次下載
    <b class='flag-5'>單片機(jī)</b>的<b class='flag-5'>啟動(dòng)</b>過(guò)程

    單片機(jī)啟動(dòng)流程分析

    單片機(jī)啟動(dòng)流程概述單片機(jī)后一直到準(zhǔn)備好C語(yǔ)言運(yùn)行環(huán)境并跳轉(zhuǎn)到main函數(shù)執(zhí)行總共經(jīng)歷了5個(gè)步驟:1.內(nèi)核初始化;2.強(qiáng)制PC指針指向
    發(fā)表于 11-17 11:36 ?10次下載
    <b class='flag-5'>單片機(jī)</b><b class='flag-5'>啟動(dòng)</b><b class='flag-5'>流程</b>分析

    STM32 單片機(jī)啟動(dòng)流程

    STM32 單片機(jī)啟動(dòng)流程剛接觸ARM的cortex-m系列單片機(jī)時(shí),被告知一切都從main() 函數(shù)開(kāi)始,要將程序?qū)懺趍ain()函數(shù)中。而仿真時(shí)也貌似是從main() 函數(shù)開(kāi)始的,
    發(fā)表于 11-19 10:21 ?35次下載
    STM32 <b class='flag-5'>單片機(jī)</b><b class='flag-5'>啟動(dòng)</b><b class='flag-5'>流程</b>

    單片機(jī)啟動(dòng)過(guò)程

    啟動(dòng)過(guò)程簡(jiǎn)介單片機(jī)啟動(dòng)過(guò)程是加后,先運(yùn)行芯片內(nèi)部固有程序(這個(gè)程序是用戶訪問(wèn)不到也改寫(xiě)不了的),即啟動(dòng)代碼。
    發(fā)表于 11-19 12:06 ?55次下載
    <b class='flag-5'>單片機(jī)</b>的<b class='flag-5'>啟動(dòng)</b>過(guò)程

    單片機(jī)中程序和數(shù)據(jù)存放位置、與電腦內(nèi)存和硬盤(pán)的類比,單片機(jī)和計(jì)算機(jī)程序啟動(dòng)流程對(duì)比

    單片機(jī)中程序和數(shù)據(jù)存放位置、與電腦內(nèi)存和硬盤(pán)的類比,單片機(jī)和計(jì)算機(jī)程序啟動(dòng)流程對(duì)比
    發(fā)表于 11-26 17:51 ?14次下載
    <b class='flag-5'>單片機(jī)</b>中程序和數(shù)據(jù)存放位置、與電腦內(nèi)存和硬盤(pán)的類比,<b class='flag-5'>單片機(jī)</b>和計(jì)算機(jī)程序<b class='flag-5'>啟動(dòng)</b><b class='flag-5'>流程</b>對(duì)比

    STM32的啟動(dòng)過(guò)程如何分析

    本文分析STM32單片機(jī)從上運(yùn)行的過(guò)程,目的在于了解STM32單片機(jī)啟動(dòng)到運(yùn)行的整個(gè)過(guò)程。
    的頭像 發(fā)表于 02-10 10:48 ?1237次閱讀
    STM32的<b class='flag-5'>啟動(dòng)</b>過(guò)程如何分析