一個(gè)朋友前幾天對(duì)我說(shuō),想使用 ARM11 內(nèi)核的 MCU 做一樣?xùn)|西,能不能幫他找個(gè)支持的開(kāi)發(fā)工具,我記得 IAR 的支持 ARM11 ,就讓他試試看,結(jié)果這位老兄試了一下嚴(yán)重不適應(yīng),問(wèn)了很多細(xì)節(jié),結(jié)果我也不太明白 ,所以特地下載了一個(gè) IAR EW For ARM 的學(xué)習(xí)版研究一下,有 32K 代碼限制,不過(guò)這不影響我們的學(xué)習(xí) 。
安裝好軟件后,先創(chuàng)建一個(gè)只有 main 函數(shù)的工程,隨便選了一款 MCU,編譯后模擬運(yùn)行,居然就直接跳到 main
里面了,這是很奇怪的事情,我對(duì) Keil 的 MDK 要熟悉一點(diǎn),不管是什么 MCU
,都應(yīng)該有個(gè)硬件初始化的啟動(dòng)文件才對(duì)?。繎?yīng)該先執(zhí)行初始化硬件、向量表、堆棧等等的工作,然后才能跳轉(zhuǎn)到 main 執(zhí)行,所以我也暈了。
然后仔細(xì)看手冊(cè),原來(lái)系統(tǒng)有默認(rèn)設(shè)置,模擬仿真時(shí)是直接運(yùn)行 main 處才停下來(lái),將這個(gè)默認(rèn)選項(xiàng)去掉(在項(xiàng)目的 option 里面,debug 欄的 Run to),這樣才能真正從復(fù)位開(kāi)始運(yùn)行。

再次仿真用單步執(zhí)行,發(fā)現(xiàn)在 main
之前,系統(tǒng)做了很多工作,包括硬件初始化、向量設(shè)置、堆棧和堆的創(chuàng)建和初始化,但僅僅是在反匯編窗口看到代碼,卻沒(méi)有源文件的代碼同步顯示,奇哉怪哉?拜
托!這是我的項(xiàng)目哎,我還沒(méi)寫這些咚咚,你給我瞎添什么代碼呀?難怪我的那位老友嚴(yán)重不適應(yīng),我也嚴(yán)重不適應(yīng) 。 只好耐著性子再看手冊(cè),直接用仿真跟蹤到的那些標(biāo)號(hào)來(lái)搜索,找到了啟動(dòng)這個(gè)方面的描述。
原來(lái)和 keil 不同,keil 是在創(chuàng)建項(xiàng)目的時(shí)候,給你添加一個(gè)啟動(dòng)文件,這個(gè)文件直接列在項(xiàng)目表上,讓你一目了然。而 IAR
使用了“弱函數(shù)”的概念,即系統(tǒng)事先定義好一些標(biāo)號(hào),作為啟動(dòng)的選項(xiàng)。如果你用這些標(biāo)號(hào)編寫了自己的啟動(dòng)函數(shù),則編譯器就會(huì)使用你的啟動(dòng)函數(shù)來(lái)初始化系
統(tǒng),如果你沒(méi)有寫,則系統(tǒng)有提供默認(rèn)的函數(shù)源代碼來(lái)幫你完成初始化。
這樣的好處是對(duì)于嵌入式的初學(xué)者來(lái)說(shuō),先跳過(guò)麻煩的硬件初始化,直接讓C程序運(yùn)行起來(lái),就像傻瓜相機(jī),不用調(diào)光圈和焦距,直接按下快門也能得到一張說(shuō)的過(guò)
去的照片。而且,對(duì)專業(yè)工程師來(lái)說(shuō),使用“弱函數(shù)”的概念就可以避免傻瓜相機(jī)不能細(xì)調(diào)的尷尬,它提供了你自定義啟動(dòng)的能力,一樣可以做到很專業(yè)。原來(lái)如
此,怪咱們沒(méi)有耐心認(rèn)真去看手冊(cè)。
不過(guò),在這點(diǎn)上,我認(rèn)為 keil 要貼心一點(diǎn),它將默認(rèn)的啟動(dòng)文件顯示地拷貝到項(xiàng)目中,讓你比較清楚啟動(dòng)流程。而 IAR
將這點(diǎn)隱藏了,不認(rèn)真看手冊(cè),就會(huì)讓使用者有些糊涂。不過(guò),這個(gè)和老外的做事性格有關(guān)系,我們風(fēng)風(fēng)火火的風(fēng)格估計(jì)老外也沒(méi)預(yù)計(jì)到,他們可能認(rèn)為使用者應(yīng)該
去仔細(xì)閱讀手冊(cè) 。
---------------------------------------------------------------------------------------------
下面介紹一下幾個(gè)啟動(dòng)文件,來(lái)自 IAR 手冊(cè)中的描述:
本章節(jié)描述了在運(yùn)行環(huán)境活動(dòng)期間,你的程序的啟動(dòng)和終止。程序代碼的啟動(dòng)和終止是位于源文件 cstartup.s、cmain.s、cexit.s 和 low_level_init.c 中,它們位于arm\ src\ lib目錄下。
而對(duì)于Cortex-M內(nèi)核,下列其中一個(gè)文件是用來(lái)代替 cstartup.s:thumb\cstartup_M.s 或 thumb\cstartup_M.c。有關(guān)如何自定義系統(tǒng)啟動(dòng)代碼的信息,請(qǐng)參閱76頁(yè)的 - 自定義系統(tǒng)初始化。
在系統(tǒng)啟動(dòng)過(guò)程期間,一個(gè)初始化序列會(huì)在進(jìn)入 main 之前執(zhí)行。這個(gè)序列對(duì)目標(biāo)硬件和C/C++ 環(huán)境的需要進(jìn)行必要的初始化。
1、 CPU在復(fù)位時(shí)跳到程序的入口點(diǎn):即系統(tǒng)啟動(dòng)代碼中的標(biāo)號(hào) __iar_program_start 處。
2、異常堆棧指針是初始化到每個(gè)相應(yīng)部分的尾部
3、堆棧指針是初始化到CSTACK塊的尾部
4、如果你定義了 __iar_program_start 函數(shù),則它被調(diào)用,這提供了一個(gè)機(jī)會(huì)來(lái)執(zhí)行早期的初始化。
注意:對(duì)于 Cortex-M 設(shè)備,上面列表中的第二條是不正確的。第一條和第三條的處理也稍微有點(diǎn)不同。在復(fù)位后,CPU初始化PC和SP的值來(lái)自于向量表( __vector_table ),它們定義在 cstartup_M.c 文件中。
你可能需要自定義系統(tǒng)的初始化代碼。例如,你的應(yīng)用程序可能需要初始化內(nèi)存映射特殊功能寄存器(SFRs),或省略掉 cstartup 中默認(rèn)的數(shù)據(jù)初始化部分。
為此,您可以提供一個(gè)定制版本的程序 __low_level_init,即在 cmain.s
部分被調(diào)用之前,對(duì)數(shù)據(jù)部分實(shí)施初始化。應(yīng)當(dāng)避免直接修改cstartup文件。處理系統(tǒng)啟動(dòng)的代碼位于源文件 cstartup.s 和
low_level_init.c 中,在 arm\src\lib 目錄下。
產(chǎn)品中提供了兩個(gè)框架的低級(jí)別初始化文件:一個(gè)C源文件 low_level_init.c 和一個(gè)替代的匯編程序源文件
low_level_init.s。后者是屬于預(yù)置運(yùn)行環(huán)境的一部分。對(duì)使用C源代碼版本的唯一限制是在文件中不能使用靜態(tài)初始化變量,在變量初始化這點(diǎn)
上尚未完成。
--------------------------------------------------------------------------------------------------
由上可以看出,在創(chuàng)建一個(gè)新項(xiàng)目后,系統(tǒng)就默認(rèn)使用了上面幾個(gè)文件,但是并沒(méi)有顯示地添加到項(xiàng)目表中。所以可以將上面幾個(gè)文件拷貝到你的項(xiàng)目目錄中,然后
再手工添加到你的項(xiàng)目中,此時(shí)就可以修改它們的內(nèi)容,來(lái)定制你自己的初始化流程。注意:千萬(wàn)不要將 IAR
安裝目錄下的這幾個(gè)源文件加到項(xiàng)目中,而是必須用拷貝的方式來(lái)復(fù)制這些文件。免得不小心修改了源文件的內(nèi)容,導(dǎo)致其它項(xiàng)目使用這些默認(rèn)文件時(shí)產(chǎn)生錯(cuò)誤。
上面提到的這些文件在學(xué)習(xí)版中可能沒(méi)有 C 語(yǔ)言的版本,反正我沒(méi)看到,但是提供了一些匯編的版本,這已經(jīng)夠用了。在仔細(xì)看完 IAR
的手冊(cè)之后,感覺(jué)這套工具很不錯(cuò),尤其對(duì)學(xué)習(xí)嵌入式的人來(lái)說(shuō),這個(gè) IAR 的學(xué)習(xí)版提供了絕佳的學(xué)習(xí)環(huán)境。而對(duì)于我們這些 DIY
愛(ài)好者來(lái)說(shuō),它雖然有 32K 代碼的限制,但沒(méi)有使用時(shí)間上的限制, 所以也能用它制作出很棒的東西了。
|