當(dāng)前位置:首頁(yè) > 單片機(jī) > 單片機(jī)
[導(dǎo)讀]1.1 啟動(dòng)代碼內(nèi)容1) 硬件初始化:最起碼的是要初始化堆棧指針。2) C語(yǔ)言環(huán)境 :在main函數(shù)調(diào)用之前要完成對(duì)一些變量的初始化。3) 應(yīng)用初始化: 這主要取決于你的應(yīng)用。比如設(shè)置系統(tǒng)的晶振、時(shí)鐘。1.2 圖解M3啟動(dòng)過(guò)程1)

1.1 啟動(dòng)代碼內(nèi)容

1) 硬件初始化:最起碼的是要初始化堆棧指針。

2) C語(yǔ)言環(huán)境 :在main函數(shù)調(diào)用之前要完成對(duì)一些變量的初始化。

3) 應(yīng)用初始化: 這主要取決于你的應(yīng)用。比如設(shè)置系統(tǒng)的晶振、時(shí)鐘。


1.2 圖解M3啟動(dòng)過(guò)程

1)程序開(kāi)始運(yùn)行,系統(tǒng)啟動(dòng)代碼首先要完成硬件初始化,比如說(shuō)對(duì)堆棧的初始化。圖中顯示初始化堆棧指針為之前

預(yù)先定義好堆棧區(qū)域的末尾(M3內(nèi)核堆棧時(shí)向下生長(zhǎng))。


2)初始化變量初始值為0全局變量和靜態(tài)變量



3)初始化變量初始值為非0的變量,鏈接器將存儲(chǔ)在ROM的初始值復(fù)制到相應(yīng)的RAM中。



4)初始化應(yīng)用(可選)

5)最后調(diào)用主函數(shù)




6)附錄

關(guān)于C語(yǔ)言中變量的存儲(chǔ)區(qū)域。

1、初始化和非初始化的變量都存放在內(nèi)存區(qū)(RAM);

2、全局const被存放在代碼區(qū)。

3、static存放在內(nèi)存區(qū)(RAM)

4、對(duì)于數(shù)量少的局部變量一般是寄存器操作

5、對(duì)于數(shù)據(jù)量大的局部變量則采用是堆棧操作。


1.3 M3啟動(dòng)代碼實(shí)例分析


下面例子為在iar下,由EFM32芯片(M3內(nèi)核)廠商提供的啟動(dòng)代碼startup_efm32g.s。IDE為IARFORARM6.0。其中

ROM(0x00000000-(0x20000000-1));

RAM(0X20000000-(0X20000000+0X00004000-1))

首先,上電后程序從向量表中取出復(fù)位異常ISR地址,跳轉(zhuǎn)至異常服務(wù)程序Reset_Handler,程序如下:

[cpp]view plaincopyprint?

PUBWEAKReset_Handler

SECTION.text:CODE:REORDER(2)

Reset_Handler

LDRR0,=SystemInit

BLXR0

LDRR0,=__iar_program_start

BXR0



其中Reset_Handler為PUBWEAK,即可以被我們重寫(xiě)的同名函數(shù)覆蓋。一般來(lái)說(shuō),我們可以直接使用EFM32提供的Reset_Handler??梢钥吹皆趕tartup_efm32.s中Reset_Handler只是調(diào)用了兩個(gè)函數(shù)。通過(guò)單步調(diào)試,進(jìn)入SystemInit()。該函數(shù)在system_efm32g.c中定義,且沒(méi)有任何內(nèi)容是個(gè)空函數(shù),提供這個(gè)空函數(shù)旨在調(diào)用應(yīng)用程序前為用戶根據(jù)提供一個(gè)函數(shù)接口來(lái)完成系統(tǒng)的硬件初始化(時(shí)鐘,flash等)。SystemInit()完成之后,IAR就把大權(quán)交給了__iar_program_start這個(gè)IAR提供的“內(nèi)部函數(shù)”了,我們就跟緊這個(gè)__iar_program_start跳轉(zhuǎn),看看IAR做了什么。


我們看到IAR提供了__low_level_init這個(gè)函數(shù)進(jìn)行了“底層”的初始化,進(jìn)一步跟蹤,我們可以查到__low_level_init這個(gè)函數(shù)做了些什么?


__low_level_init出乎想象的簡(jiǎn)單,只是往R0寄存器寫(xiě)入了1,就立即執(zhí)行"BX LR"回到調(diào)用處了,接下來(lái),__iar_program_start檢查了R0是否為0,為0,則執(zhí)行_call_main,若不是0,就執(zhí)行__iar_data_init3。我在IAR
的安裝目錄IAR SystemsEmbedded Workbench 6.0 Kickstartarmsrclib下找到了IAR提供的該函數(shù)的sketch,程序內(nèi)容如下:

[cpp]view plaincopyprint?

__interworkint__low_level_init(void)

{

/*==================================*/

/*Initializehardware.*/

/*==================================*/

/*Chooseifsegmentinitialization*/

/*shouldbedoneornot.*/

/*Return:0toomitseg_init*/

/*1torunseg_init*/

return1;

}

很明顯,這個(gè)函數(shù)的目的是讓用戶選擇是否完成變量的初始化工作。如果不需初始化,可以令其return 0 。那么程序就直接_call_main跳入main函數(shù)了。至于如何修改,參見(jiàn)EWARM development Guide。我們這里選擇初始化變量,繼續(xù)單步運(yùn)行,程序進(jìn)入__iar_data_init3,匯編代碼如下


當(dāng)程序運(yùn)行到 0x5480 :0x42a1CMPR1,R4;通過(guò)查看寄存器R1的值為0x00005490,R4的值為0x000054b4,這恰好是Region#Table#Base的開(kāi)始地址和結(jié)束地址。程序繼續(xù)往下走,如果R1=R4,則彈出R4和LR,直接進(jìn)入main。顯然R1此時(shí)不等于R4,且繼續(xù)往下運(yùn)行R0=R1+4,將R1地址中的內(nèi)容裝載至R2(即從(Region#Table#Base)取出一個(gè)參數(shù)送人R2),再令R1=R1+R2,跳轉(zhuǎn)至R1地址處即進(jìn)到__iar_zero_init3函數(shù)。


在__iar_zero_init中,取出(Region#Table#Base)中的第一個(gè)參數(shù)放入R1,另一個(gè)參數(shù)放入R2。同時(shí)R0進(jìn)行了兩次后索引,即R0=R0+8。通過(guò)查看寄存器,R2為0x200000AC,為該系統(tǒng)的RAM區(qū)。存在循環(huán):

[cpp]view plaincopyprint?

0X3B8MOVSR3,#0

0X3BASTR.WR3,[R2],#0X04

0X3BESUBSR1,R1,#0X04

0X3C0BNE.N0X3B8

for(;R1!=0;R2=R2+4,R1=R1-4)

{

*R2=0

}

可以看出,該函數(shù)是將一段內(nèi)存區(qū)域清零,其中R2為內(nèi)存區(qū)域的首地址,R1為清零內(nèi)存區(qū)域的大小。清零完成后,又回到__iar_data_init3。將R0的值賦給R1,此時(shí)R1為Region#Table#Base的新的首地址,別忘了在__iar_zero_init從Region#Table#Base取了兩個(gè)值,R0后索引了兩次。程序繼續(xù)比較R1和R4的值,不相等。再(Region$|$Table$|$Base)取出參數(shù)賦給R1,BX R1。程序進(jìn)入__iar_copy_init3。


可以看出與__iar_zero_init3中取參數(shù)的幾乎一樣:先取出大小,隨后取出了地址——只不過(guò)這里多出了1個(gè)地址,沒(méi)錯(cuò)這就是"copy",其中R1為copy字節(jié)數(shù)目,R2為存儲(chǔ)變量初始值的FLASH首地址(source),R3為變量的內(nèi)存地址區(qū)(destination)。復(fù)制過(guò)程代碼循環(huán)為:

[cpp]view plaincopyprint?

0x2612LDR.WR4,[R2],#0X04

0X2616STR.WR4,[R3],#0X04

0X261ASUBSR1,R1,#4

0X261CBNE.N0X2612

for(;R1!=0;R2=R2+4,R3=R3+4,R1=R1-4)

{

*R3=*R2;

}

讀到這里,我們應(yīng)該可以猜到IAR的意圖了:__iar_data_init3一開(kāi)始加載了0x0800'7C78至R0,0x0800'7C9C至R4,[R0,R4]就是一段啟動(dòng)代碼區(qū),在這個(gè)區(qū)域內(nèi)保存了要“處理”的所有地址與信息——執(zhí)行的函數(shù)地址或者參數(shù),實(shí)際上,這片區(qū)域也有一個(gè)名字,叫做:(Region#Table#Base)。在這個(gè)區(qū)域內(nèi),程序以R0為索引,R4為上限,當(dāng)R0=R4,__iar_data_init3執(zhí)行完畢,跳轉(zhuǎn)至main()函數(shù)。

1.4 總結(jié)
通過(guò)上述分析我們可以看到Region#Table#Base保存了__iar_data_init3、__iar_data_copy的地址,同時(shí)還有函數(shù)所需的__iar_data_init3的FLASH地址和清零字節(jié)的個(gè)數(shù)、以及__iar_data_copy源地址和目的地址以及復(fù)制的字節(jié)個(gè)數(shù)信息。
總之,IAR在啟動(dòng)main()函數(shù)以前,執(zhí)行了Reset_Handler,調(diào)用SystemInit(),并轉(zhuǎn)入__iar_program_start中執(zhí)行__low_level_init與__iar_data_init3,并在__iar_data_init3中,先后調(diào)用__iar_zero_init3與__iar_copy_init3對(duì)全局變量、全局已初始化變量進(jìn)行相應(yīng)的初始化操作。最后,調(diào)用main()函數(shù)執(zhí)行。

1.5 思考
思考1
為什么進(jìn)入__iar_data_init3和__iar_data_copy時(shí),只選擇將R4,和LR壓棧?
壓棧R4可以很簡(jiǎn)單的理解,因?yàn)槌绦蛑杏玫搅嗽摷拇嫫鳎栽谶M(jìn)入調(diào)用函數(shù)時(shí)把它壓入棧保護(hù),但是為什么不壓棧R0-R3呢?網(wǎng)上搜了一遭,發(fā)現(xiàn)得從ATPCS ( ARM-THUMB procedure call standard)說(shuō)起。其中ATPCS規(guī)定寄存器使用有如下規(guī)則:
1. 子程序間通過(guò)寄存器 R0-- R3 來(lái)傳遞參數(shù),被調(diào)用的子程序在返回前無(wú)需恢復(fù)寄存器 R0-R3 的內(nèi)容。
2. 在子程序中,使用寄存器 R4 R11 來(lái)保存局部變量。 如果在子程序中使用到了其中的寄存器 , 子程序進(jìn)入時(shí)必須保存這些寄存器的值, 在返回前必須恢復(fù)這些寄存器的值; 對(duì)于子程序中沒(méi)有用到的寄存器則不必進(jìn)行這些操作。


思考2
__iar_data_init3、__iar_data_copy和__low_level_init這些函數(shù)在哪里?
之前在iar的安裝目錄IAR SystemsEmbedded Workbench 6.0 Kickstartarmsrclib下找了很久,都沒(méi)有找到__iar_data_init3、__iar_data_copy這兩個(gè)函數(shù),對(duì)于__low_level_init,我工程里面也沒(méi)有設(shè)置改文件的包含路徑。所以敢肯定,啟動(dòng)代碼中調(diào)用的函數(shù)非這個(gè)函數(shù)。

最后,通過(guò)設(shè)置project->options->linker->list。選中Module selection。重新編譯工程。在工程目錄debug->list文件下找到*.log文件,查看鏈接器的鏈接日志。在*.log文件中詳細(xì)列舉了每個(gè)目標(biāo)文件的load目錄和import和definition symbol。在這個(gè)文件里,終于找到了它們的身影。







可以看到

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車(chē)的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車(chē)技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車(chē)工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車(chē)。 SODA V工具的開(kāi)發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車(chē) 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開(kāi)幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉