大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家分享的是在IAR開(kāi)發(fā)環(huán)境下將盡可能多的代碼重定向到RAM中執(zhí)行的方法。
最近和同事在討論一個(gè)客戶案例,客戶 APP 工程是基于 IAR 開(kāi)發(fā)環(huán)境,客戶希望將工程里盡可能多的代碼都重定向到 RAM 里執(zhí)行,僅留必要或者指定的源文件代碼在 Flash 中執(zhí)行。這個(gè)需求和痞子衡舊文 《在IAR下將關(guān)鍵函數(shù)重定向到RAM中執(zhí)行的方法》 實(shí)現(xiàn)正好相反,正常需求都是指定一些代碼重定向到 RAM,客戶這次卻是要保留一些指定代碼在 Flash 中,其余全部都重定向到 RAM。
客戶的這個(gè)需求原則上我們還是可以用老方法去做,即在 IAR 鏈接文件里將除了指定源文件外的其它 object 全部加入 initialize by copy 語(yǔ)句里,或者直接代碼里對(duì)相關(guān)函數(shù)加 __ramfunc 或者 section 屬性,但顯然這種方式手工活太多比較繁瑣,有沒(méi)有更人性化的方式呢?當(dāng)然有!這就是痞子衡今天要聊的話題:
- Note 1:閱讀本文前需要對(duì) 《IAR鏈接文件(.icf)》、《IAR映射文件(.map)》 這兩種文件有所了解。Note 2:本文使用的 IAR EWARM 軟件版本是 v9.50.1。
一、代碼全部重定向問(wèn)題
在話題開(kāi)始之前,我們先討論一個(gè)問(wèn)題。我們是否可以完全借助 IAR 自身特性將 APP 工程代碼全部重定向到 RAM 里執(zhí)行(即 CPU 不會(huì)在 Flash 里執(zhí)行任何代碼)?在回答這個(gè)問(wèn)題之前,我們先來(lái)回憶一下代碼重定向到底是如何完成的。一些被指定重定向的代碼在鏈接時(shí)會(huì)被放到 RAM 區(qū)執(zhí)行,但是會(huì)在 Flash 里留下其代碼體機(jī)器碼數(shù)據(jù),這些數(shù)據(jù)需要從 Flash 里被拷貝到 RAM 里,這個(gè)拷貝動(dòng)作是 IAR 底層函數(shù) __iar_data_init3() 完成的,詳見(jiàn)痞子衡舊文 《IAR啟動(dòng)函數(shù)流程之段初始化函數(shù)__iar_data_init3實(shí)現(xiàn)》 。
很顯然 IAR 底層函數(shù) __iar_data_init3() 也是 APP 工程代碼的一部分,它是需要在 Flash 里執(zhí)行的,它沒(méi)法被重定向(因?yàn)闆](méi)有代碼負(fù)責(zé)將這個(gè)底層函數(shù)機(jī)器碼再拷貝到 RAM),鑒于此,我們也就沒(méi)法完全利用 IAR 自身特性去做整個(gè) APP 工程代碼的重定向。
如果想實(shí)現(xiàn)整個(gè) APP 工程的重定向,則必須額外設(shè)計(jì)一個(gè)在 Flash 里執(zhí)行的二級(jí) Loader 工程,由這個(gè) Loader 工程將 APP 工程全部數(shù)據(jù)從 Flash 里全部拷貝到 RAM 里再跳轉(zhuǎn),具體實(shí)現(xiàn)可見(jiàn)痞子衡舊文 《KBOOT形態(tài)(ROM/Bootloader/Flashloader)》 里的 2.3.1 小節(jié)。
二、IAR鏈接語(yǔ)法 initialize {} except {}
現(xiàn)在回到正題,要想實(shí)現(xiàn)客戶需求,我們還得借助 IAR 自身,翻看 IAR SystemsEmbedded Workbench 9.50.1armdocEWARM_DevelopmentGuide.ENU 手冊(cè),可以找到如下關(guān)于 initialize 語(yǔ)法的定義,其中有可選的 except 語(yǔ)句,顧名思義,就是可以讓一些指定的 object/section 不做 initialize 規(guī)定的動(dòng)作,顯然我們可以利用它來(lái)實(shí)現(xiàn)客戶需求。
三、initialize {} except {} 語(yǔ)法實(shí)踐
現(xiàn)在讓我們?cè)囋囘@個(gè)語(yǔ)法,我們以 SDK_2_16_000_MIMXRT1170-EVKBboardsevkbmimxrt1170demo_appshello_worldcm7iar 工程的 flexspi_nor_debug build 為例,其配套鏈接文件是 MIMXRT1176xxxxx_cm7_flexspi_nor.icf,全部的 readonly 段分配在 0x30000000 - 0x30FBFFFF 空間(在 Flash 中),全部的 readwrite 段分配在 0x20000000 - 0x2003FFFF 空間(在 DTCM 中)。
3.1 試驗(yàn):將 readonly 放入 initialize by copy 中
先來(lái)做第一個(gè)實(shí)驗(yàn),不用 except 語(yǔ)法,就是將 readonly 也放入 initialize by copy 中,看看是不是能夠?qū)?APP 中全部代碼重定向到 DTCM。
編譯鏈接后,打開(kāi) map 文件,可以看到 Flash 地址空間內(nèi)僅剩下 section .boot_hdr.conf 和 .boot_hdr.ivt(這兩個(gè)段沒(méi)被重定向,主要原因是鏈接文件里沒(méi)有用 readonly 修飾) 以及和 IAR 底層函數(shù)拷貝動(dòng)作相關(guān)的源文件函數(shù)(這里可以便于我們識(shí)別哪些函數(shù)是和初始化階段拷貝動(dòng)作相關(guān)的)。
這個(gè)結(jié)果表明,即使不顯式地寫(xiě)出 except 語(yǔ)句,那些和拷貝動(dòng)作相關(guān)的函數(shù)也會(huì)自動(dòng)從 readonly 段里被挑出來(lái),不受 initialize by copy 的影響。
3.2 試驗(yàn):用 except 挑出 RT 啟動(dòng)頭
上一個(gè)測(cè)試結(jié)果在 i.MXRT 下并不能正常工作,除了沒(méi)有將 .boot_hdr.xxx 啟動(dòng)頭全部放在 Flash 指定偏移處之外(兩個(gè)沒(méi)加 readonly 修飾的僥幸放對(duì)了),ARM 中斷向量表也沒(méi)有放在指定位置,會(huì)影響復(fù)位函數(shù) Reset_Handler 的正常執(zhí)行,因此在 i.MXRT 上我們至少應(yīng)該將如下段放進(jìn) except 列表里:
編譯鏈接后,這時(shí)候啟動(dòng)頭以及中斷向量表就被保留在 Flash 指定偏移處了,這個(gè)程序下載進(jìn) Flash 是可以被芯片正常啟動(dòng)執(zhí)行的。
3.3 試驗(yàn):用 except 挑出指定源文件
此時(shí)終于進(jìn)入到客戶需求實(shí)現(xiàn)階段了,將需要被保留在 Flash 執(zhí)行的源文件/函數(shù)全部列出備用。以 hello_world 工程為例,我們就將 hello_world.c 源文件里的代碼全部保留在 Flash 里,這時(shí)候只需要將其加進(jìn) except 列表里即可:
編譯鏈接后,可以看到 hello_world.o 里的 ro code 和 const data 均被顯式地保留在 Flash 區(qū)域了,客戶需求得以完美實(shí)現(xiàn)。
四、如何重定向到非RW段所在RAM?
前面借助 IAR 特性實(shí)現(xiàn)的代碼重定向均是將代碼放到 RW 段所在 RAM 區(qū)(DTCM),但是對(duì)于 i.MX RT 這樣包含多個(gè)非連續(xù) RAM 空間的芯片來(lái)說(shuō),如果客戶希望是重定向到非 RW 段所在的 RAM 空間的話,那情況就大不同了。
關(guān)于將 APP 工程里一些源文件重定向到任意指定的 RAM,由于 IAR 自身的限制,痞子衡寫(xiě)過(guò)兩篇文章 《在IAR下將整個(gè)源文件代碼重定向到任意RAM中的方法》、《在IAR下手動(dòng)拷貝自定義程序段到RAM中執(zhí)行的方法》 介紹過(guò)實(shí)現(xiàn)方法,就是需要在相應(yīng)代碼里增加一些自定義段修飾,但是這種方法顯然不適用客戶這種需求(同樣是因?yàn)槭止せ钐啾容^繁瑣的原因)。
那這種需求該如何實(shí)現(xiàn)呢?這里留下一個(gè)思路,可以結(jié)合 IAR 的用戶代碼庫(kù)制作,將無(wú)需重定向的代碼之外的全部代碼匯編成一個(gè)庫(kù)(Lib),然后對(duì)這個(gè) Lib 整體再進(jìn)行重定向,思路僅供參考。
至此,在IAR開(kāi)發(fā)環(huán)境下將盡可能多的代碼重定向到RAM中執(zhí)行的方法痞子衡便介紹完畢了,掌聲在哪里~~~