加入星計劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴散
  • 作品版權(quán)保護
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
    • MCU啟動過程
    • 啟動代碼
    • 調(diào)試
    • 注意事項
    • 總結(jié)
  • 推薦器件
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

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

2023/08/14
2064
閱讀需 12 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

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

MCU啟動過程

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

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

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

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

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

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

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

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

更具體一點:

當MCU復位之后,PC指針會指向?qū)膹臀幌蛄?,然后運行對應的啟動代碼(startup code),啟動代碼首先會初始化Stack pointer指向指定Stack區(qū)域的末尾。

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

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

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

啟動代碼

通常情況下,如果ICF文件中添加了initialize by copy 命令,linker會自動選擇并添加對應的啟動代碼來完成對應的啟動過程。對應的啟動代碼通過庫文件的方式進行l(wèi)ink。對應的啟動代碼在安裝目錄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)

對應的啟動代碼和相關(guān)文件信息會在map文件里面列出來:

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

調(diào)試

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

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

如果對應的MCU有FPU,__iar_program_start首先會調(diào)用__iar_init_vfp對FPU進行初始化:

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

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

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

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

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

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

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

注意事項

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

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

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

在IAR中,__iar_program_start是默認的程序開始標簽。如果代碼中使用了其他程序開始標簽,可以通過鏈接器選項--entry來指定相應的程序開始標簽。

總結(jié)

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

推薦器件

更多器件
器件型號 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊 ECAD模型 風險等級 參考價格 更多信息
AFBR-57B4APZ 1 Broadcom Limited Transceiver,
$69.51 查看
VC-801-EAE-KAAN-25M0000000 1 Vectron International CMOS Output Clock Oscillator, 0.032768MHz Min, 125MHz Max, 25MHz Nom, ROHS COMPLIANT, HERMETIC SEALED, SMALL, CERAMIC PACKAGE-4
暫無數(shù)據(jù) 查看
TLE9271QXV33XUMA1 1 Infineon Technologies AG Interface Circuit, PQCC48, VQFN-48
暫無數(shù)據(jù) 查看

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

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

Arm64 棧回溯
  • 查看更多