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

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

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

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

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

MCU啟動(dòng)過程

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

當(dāng)MCU復(fù)位之后,MCU會從對應(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í),它會將程序計(jì)數(shù)器(PC)設(shè)置為復(fù)位向量的地址,從而開始執(zhí)行存儲在這個(gè)地址上的指令。

復(fù)位向量通常位于MCU的存儲器中的固定位置,通常是在芯片的起始位置。這確保了在復(fù)位時(shí)能夠始終從相同的地址開始執(zhí)行,從而確??煽康南到y(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的變量對應(yīng)的RAM區(qū)域會清零,初始值為非0的變量,會從ROM拷貝到RAM(注意:如果__low_level_init函數(shù)返回0,這一步將會跳過)。

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

更具體一點(diǎn):

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

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

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

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

啟動(dòng)代碼

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

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

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

調(diào)試

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

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

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

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

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

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

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

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

最后__call_main會調(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ù)位后會從中斷向量表的0地址偏移處獲取值并賦給MSP寄存器。因此,上述啟動(dòng)代碼和啟動(dòng)過程中并未顯式體現(xiàn)這一步驟。然而,若需要手動(dòng)對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"命令。

對于初始化操作,用戶可以通過實(shí)現(xiàn)__low_level_init函數(shù)來進(jìn)行。特別是對于支持ECC(Error Correction Code)機(jī)制的MCU的RAM,需要在__low_level_init函數(shù)中根據(jù)ECC的位寬對RAM區(qū)域進(jìn)行一次寫操作,以避免后續(xù)RAM操作引發(fā)ECC錯(cuò)誤。需要注意的是,__low_level_init函數(shù)在全局和靜態(tài)變量初始化之前執(zhí)行,因此其中不能使用這些全局和靜態(tài)變量。此外,__low_level_init函數(shù)的返回值決定是否需要對全局和靜態(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)會指向相應(yīng)的復(fù)位向量,并開始執(zhí)行啟動(dòng)代碼(startup code)。如果MCU支持浮點(diǎn)單元(FPU),則在啟動(dòng)過程中,首先會調(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來進(jìn)行全局和靜態(tài)變量的初始化。在__iar_data_init3中,首先會調(diào)用__iar_zero_init3來初始化初始值為0的全局和靜態(tài)變量,隨后會調(diào)用__iar_copy_init3來初始化初始值為非0的全局和靜態(tài)變量。最終,在啟動(dòng)過程的最后階段,會通過調(diào)用__call_main來跳轉(zhuǎn)到main函數(shù),從而開始執(zhí)行主程序。

推薦器件

更多器件
器件型號 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊 ECAD模型 風(fēng)險(xiǎn)等級 參考價(jià)格 更多信息
SN74LV244APW 1 Texas Instruments Eight-channel 2-V to 5.5-V buffers with tri-state outputs 20-TSSOP -40 to 125

ECAD模型

下載ECAD模型
$0.83 查看
XRCGB24M000F3A00R0 1 Murata Manufacturing Co Ltd Parallel - Fundamental Quartz Crystal, 24MHz Nom, ROHS AND REACH COMPLIANT, SMALL, SMD, 4 PIN

ECAD模型

下載ECAD模型
$0.45 查看
X1G004171004700 1 Seiko Epson Corporation CMOS Output Clock Oscillator,
$2.94 查看

相關(guān)推薦

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

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

Arm64 ?;厮?>
				</a>
							</li>
						<li id=
  • Linux BSP實(shí)戰(zhàn)課(中斷篇):中斷控制器的驅(qū)動(dòng)實(shí)現(xiàn)
  • 查看更多