• 正文
    • MCU啟動(dòng)過程
    • 啟動(dòng)代碼
    • 調(diào)試
    • 注意事項(xiàng)
    • 總結(jié)
  • 推薦器件
  • 相關(guān)推薦
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

MCU在執(zhí)行main之前做了什么?

2023/08/14
1784
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

本文以Arm Cortex-M為例,介紹了在IAR Embedded Workbench中微控制器MCU)的啟動(dòng)過程。在MCU復(fù)位后,程序計(jì)數(shù)器(PC)會(huì)指向相應(yīng)的復(fù)位向量,并開始執(zhí)行啟動(dòng)代碼(startup code)。如果MCU支持浮點(diǎn)單元(FPU),則在啟動(dòng)過程中,首先會(huì)調(diào)用__iar_init_vfp來初始化FPU,然后繼續(xù)執(zhí)行__iar_program_start。接著,__iar_program_start會(huì)調(diào)用__cmain函數(shù)。在__cmain中,會(huì)先調(diào)用__low_level_init函數(shù),然后調(diào)用__iar_data_init3來進(jìn)行全局和靜態(tài)變量的初始化。在__iar_data_init3中,首先會(huì)調(diào)用__iar_zero_init3來初始化初始值為0的全局和靜態(tài)變量,隨后會(huì)調(diào)用__iar_copy_init3來初始化初始值為非0的全局和靜態(tài)變量。最終,在啟動(dòng)過程的最后階段,會(huì)通過調(diào)用__call_main來跳轉(zhuǎn)到main函數(shù),從而開始執(zhí)行主程序。

MCU啟動(dòng)過程

MCU啟動(dòng)過程指的是從MCU復(fù)位到main函數(shù)之前的過程。

當(dāng)MCU復(fù)位之后,MCU會(huì)從對(duì)應(yīng)的復(fù)位向量開始運(yùn)行,初始化Stack pointer指向指定Stack區(qū)域的末尾,然后調(diào)用__low_level_init函數(shù)進(jìn)行相關(guān)的初始化。

(在微控制器(Microcontroller,縮寫為MCU)中,復(fù)位向量(Reset Vector)是一個(gè)特殊的內(nèi)存地址,用于指示MCU在復(fù)位或啟動(dòng)時(shí)應(yīng)該開始執(zhí)行的第一條指令。當(dāng)MCU發(fā)生復(fù)位事件(如上電復(fù)位、外部復(fù)位、看門狗定時(shí)器復(fù)位等)時(shí),它會(huì)將程序計(jì)數(shù)器(PC)設(shè)置為復(fù)位向量的地址,從而開始執(zhí)行存儲(chǔ)在這個(gè)地址上的指令。

復(fù)位向量通常位于MCU的存儲(chǔ)器中的固定位置,通常是在芯片的起始位置。這確保了在復(fù)位時(shí)能夠始終從相同的地址開始執(zhí)行,從而確保可靠的系統(tǒng)啟動(dòng)。

復(fù)位向量的內(nèi)容可以是任何有效的機(jī)器指令,通常是一條跳轉(zhuǎn)指令(比如跳轉(zhuǎn)到主程序的入口點(diǎn)),以便MCU能夠開始執(zhí)行實(shí)際的應(yīng)用程序代碼。

總之,復(fù)位向量是一個(gè)重要的概念,它確保了在MCU復(fù)位時(shí),程序能夠從可控的、確定的位置開始執(zhí)行,從而使系統(tǒng)能夠正常啟動(dòng)并運(yùn)行。)

接下來是全局和靜態(tài)變量的初始化:初始值為0的變量對(duì)應(yīng)的RAM區(qū)域會(huì)清零,初始值為非0的變量,會(huì)從ROM拷貝到RAM(注意:如果__low_level_init函數(shù)返回0,這一步將會(huì)跳過)。

然后是C++動(dòng)態(tài)初始化:構(gòu)造靜態(tài) C++ 對(duì)象,最后會(huì)調(diào)用main函數(shù)。

更具體一點(diǎn):

當(dāng)MCU復(fù)位之后,PC指針會(huì)指向?qū)?yīng)的復(fù)位向量,然后運(yùn)行對(duì)應(yīng)的啟動(dòng)代碼(startup code),啟動(dòng)代碼首先會(huì)初始化Stack pointer指向指定Stack區(qū)域的末尾。

然后初始化初始值為0的存儲(chǔ)在RAM中的全局和靜態(tài)變量(比如 int i = 0;):

初始化初始值為非0的存儲(chǔ)在RAM中的全局和靜態(tài)變量(比如 int i = 1;),對(duì)應(yīng)的初始值從相應(yīng)的ROM拷貝到對(duì)應(yīng)的RAM:

最后,調(diào)用main函數(shù):

啟動(dòng)代碼

通常情況下,如果ICF文件中添加了initialize by copy 命令,linker會(huì)自動(dòng)選擇并添加對(duì)應(yīng)的啟動(dòng)代碼來完成對(duì)應(yīng)的啟動(dòng)過程。對(duì)應(yīng)的啟動(dòng)代碼通過庫文件的方式進(jìn)行l(wèi)ink。對(duì)應(yīng)的啟動(dòng)代碼在安裝目錄armsrclib下面:

armsrclibthumbcstartup_M.s                  (__iar_program_start)armsrclibthumbcmain.s                     (__cmain,__call_main)armsrclibruntimelow_level_init.c               (__low_level_init)armsrclibruntimedata_init.c                  (__iar_data_init3)armsrclibruntimezero_init3.c                 (__iar_zero_init3)armsrclibruntimecopy_init3.c                 (__iar_copy_init3)

對(duì)應(yīng)的啟動(dòng)代碼和相關(guān)文件信息會(huì)在map文件里面列出來:

同時(shí)map文件里面INIT TABLE章節(jié)會(huì)列出對(duì)應(yīng)的全局和靜態(tài)變量的初始化信息:初始值為0的會(huì)使用__iar_zero_init3進(jìn)行初始化,初始值為非0的會(huì)使用__iar_copy_init3進(jìn)行初始化:

調(diào)試

為了能夠調(diào)試查看對(duì)應(yīng)的啟動(dòng)代碼和啟動(dòng)過程,需要配置Debugger選項(xiàng)里面的Run to,即不要勾選Run to,這樣調(diào)試的時(shí)候復(fù)位之后PC會(huì)停在復(fù)位向量而不是main函數(shù),然后就可以調(diào)試對(duì)應(yīng)的啟動(dòng)代碼和啟動(dòng)過程。

復(fù)位之后,PC會(huì)停在復(fù)位向量Reset_Handler,Reset_Handler首先會(huì)調(diào)用SystemInit函數(shù)進(jìn)行相關(guān)的配置和初始化(這個(gè)是Cortex-M CMSIS的標(biāo)準(zhǔn)),然后會(huì)調(diào)用__iar_program_start:

如果對(duì)應(yīng)的MCU有FPU,__iar_program_start首先會(huì)調(diào)用__iar_init_vfp對(duì)FPU進(jìn)行初始化:

然后__iar_program_start會(huì)調(diào)用__cmain:

__cmain首先會(huì)調(diào)用__low_level_init(默認(rèn)實(shí)現(xiàn)為空,僅返回 1):

__cmain然后會(huì)調(diào)用__iar_data_init3進(jìn)行全局和靜態(tài)變量的初始化:

__iar_data_init3首先會(huì)調(diào)用__iar_zero_init3進(jìn)行初始值為0的全局和靜態(tài)變量的初始化:

__iar_data_init3然后會(huì)調(diào)用__iar_copy_init3進(jìn)行初始值為非0的全局和靜態(tài)變量的初始化:

最后__call_main會(huì)調(diào)用main函數(shù)跳轉(zhuǎn)到main函數(shù):

至此MCU從復(fù)位向量開始,運(yùn)行啟動(dòng)代碼之后就跳轉(zhuǎn)到main函數(shù),然后開始運(yùn)行用戶的代碼:

注意事項(xiàng)

Cortex-M的MSP賦值是通過硬件自動(dòng)操作完成的,在復(fù)位后會(huì)從中斷向量表的0地址偏移處獲取值并賦給MSP寄存器。因此,上述啟動(dòng)代碼和啟動(dòng)過程中并未顯式體現(xiàn)這一步驟。然而,若需要手動(dòng)對(duì)MSP進(jìn)行賦值(例如在bootloader跳轉(zhuǎn)到application時(shí)需要手動(dòng)為application設(shè)置MSP值),則需要在啟動(dòng)代碼的起始部分執(zhí)行這一操作。

IAR默認(rèn)的啟動(dòng)代碼是在鏈接(link)過程中由鏈接器自動(dòng)添加的。如果需要手動(dòng)進(jìn)行MSP賦值等操作,這些代碼可以在啟動(dòng)代碼的最開始部分進(jìn)行添加。此外,為了支持這種操作,需要在ICF(IAR Configuration File)文件中添加"initialize by copy"命令。

對(duì)于初始化操作,用戶可以通過實(shí)現(xiàn)__low_level_init函數(shù)來進(jìn)行。特別是對(duì)于支持ECC(Error Correction Code)機(jī)制的MCU的RAM,需要在__low_level_init函數(shù)中根據(jù)ECC的位寬對(duì)RAM區(qū)域進(jìn)行一次寫操作,以避免后續(xù)RAM操作引發(fā)ECC錯(cuò)誤。需要注意的是,__low_level_init函數(shù)在全局和靜態(tài)變量初始化之前執(zhí)行,因此其中不能使用這些全局和靜態(tài)變量。此外,__low_level_init函數(shù)的返回值決定是否需要對(duì)全局和靜態(tài)變量進(jìn)行初始化,返回1表示需要初始化,返回0表示不需要初始化。

在IAR中,__iar_program_start是默認(rèn)的程序開始標(biāo)簽。如果代碼中使用了其他程序開始標(biāo)簽,可以通過鏈接器選項(xiàng)--entry來指定相應(yīng)的程序開始標(biāo)簽。

總結(jié)

本文以Arm Cortex-M為例,介紹了在IAR Embedded Workbench中微控制器(MCU)的啟動(dòng)過程。在MCU復(fù)位后,程序計(jì)數(shù)器(PC)會(huì)指向相應(yīng)的復(fù)位向量,并開始執(zhí)行啟動(dòng)代碼(startup code)。如果MCU支持浮點(diǎn)單元(FPU),則在啟動(dòng)過程中,首先會(huì)調(diào)用__iar_init_vfp來初始化FPU,然后繼續(xù)執(zhí)行__iar_program_start。接著,__iar_program_start會(huì)調(diào)用__cmain函數(shù)。在__cmain中,會(huì)先調(diào)用__low_level_init函數(shù),然后調(diào)用__iar_data_init3來進(jìn)行全局和靜態(tài)變量的初始化。在__iar_data_init3中,首先會(huì)調(diào)用__iar_zero_init3來初始化初始值為0的全局和靜態(tài)變量,隨后會(huì)調(diào)用__iar_copy_init3來初始化初始值為非0的全局和靜態(tài)變量。最終,在啟動(dòng)過程的最后階段,會(huì)通過調(diào)用__call_main來跳轉(zhuǎn)到main函數(shù),從而開始執(zhí)行主程序。

推薦器件

更多器件
器件型號(hào) 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊(cè) ECAD模型 風(fēng)險(xiǎn)等級(jí) 參考價(jià)格 更多信息
AFBR-57B4APZ 1 Broadcom Limited Transceiver,
$69.51 查看
AFBR-5972EZ 1 Foxconn Transceiver,
$193.55 查看
SN74LVC1G14DCKRE4 1 Texas Instruments Single 1.65-V to 5.5-V inverter with Schmitt-Trigger inputs 5-SC70 -40 to 125

ECAD模型

下載ECAD模型
$0.41 查看

相關(guān)推薦

登錄即可解鎖
  • 海量技術(shù)文章
  • 設(shè)計(jì)資源下載
  • 產(chǎn)業(yè)鏈客戶資源
  • 寫文章/發(fā)需求
立即登錄

針對(duì)嵌入式人工智能,物聯(lián)網(wǎng)等專業(yè)技術(shù)分享和交流平臺(tái),內(nèi)容涉及arm,linux,android等各方面。