大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家分享的是在IAR開發環境下將盡可能多的程式碼重定向到RAM中執行的方法。
最近和同事在討論一個客戶案例,客戶 APP 工程是基於 IAR 開發環境,客戶希望將工程裡儘可能多的程式碼都重定向到 RAM 裡執行,僅留必要或者指定的原始檔程式碼在 Flash 中執行。這個需求和痞子衡舊文 《在IAR下將關鍵函式重定向到RAM中執行的方法》 實現正好相反,正常需求都是指定一些程式碼重定向到 RAM,客戶這次卻是要保留一些指定程式碼在 Flash 中,其餘全部都重定向到 RAM。
客戶的這個需求原則上我們還是可以用老方法去做,即在 IAR 連結檔案裡將除了指定原始檔外的其它 object 全部加入 initialize by copy 語句裡,或者直接程式碼裡對相關函式加 __ramfunc 或者 section 屬性,但顯然這種方式手工活太多比較繁瑣,有沒有更人性化的方式呢?當然有!這就是痞子衡今天要聊的話題:
- Note 1: 閱讀本文前需要對 《IAR連結檔案(.icf)》、《IAR對映檔案(.map)》 這兩種檔案有所瞭解。
- Note 2: 本文使用的 IAR EWARM 軟體版本是 v9.50.1。
一、程式碼全部重定向問題
在話題開始之前,我們先討論一個問題。我們是否可以完全藉助 IAR 自身特性將 APP 工程程式碼全部重定向到 RAM 裡執行(即 CPU 不會在 Flash 裡執行任何程式碼)?在回答這個問題之前,我們先來回憶一下程式碼重定向到底是如何完成的。一些被指定重定向的程式碼在連結時會被放到 RAM 區執行,但是會在 Flash 裡留下其程式碼體機器碼資料,這些資料需要從 Flash 裡被複製到 RAM 裡,這個複製動作是 IAR 底層函式 __iar_data_init3() 完成的,詳見痞子衡舊文 《IAR啟動函式流程之段初始化函式__iar_data_init3實現》 。
很顯然 IAR 底層函式 __iar_data_init3() 也是 APP 工程程式碼的一部分,它是需要在 Flash 裡執行的,它沒法被重定向(因為沒有程式碼負責將這個底層函式機器碼再複製到 RAM),鑑於此,我們也就沒法完全利用 IAR 自身特性去做整個 APP 工程程式碼的重定向。
如果想實現整個 APP 工程的重定向,則必須額外設計一個在 Flash 裡執行的二級 Loader 工程,由這個 Loader 工程將 APP 工程全部資料從 Flash 裡全部複製到 RAM 裡再跳轉,具體實現可見痞子衡舊文 《KBOOT形態(ROM/Bootloader/Flashloader)》 裡的 2.3.1 小節。
二、IAR連結語法 initialize {} except {}
現在回到正題,要想實現客戶需求,我們還得藉助 IAR 自身,翻看 \IAR Systems\Embedded Workbench 9.50.1\arm\doc\EWARM_DevelopmentGuide.ENU 手冊,可以找到如下關於 initialize 語法的定義,其中有可選的 except 語句,顧名思義,就是可以讓一些指定的 object/section 不做 initialize 規定的動作,顯然我們可以利用它來實現客戶需求。
三、initialize {} except {} 語法實踐
現在讓我們試試這個語法,我們以 \SDK_2_16_000_MIMXRT1170-EVKB\boards\evkbmimxrt1170\demo_apps\hello_world\cm7\iar 工程的 flexspi_nor_debug build 為例,其配套連結檔案是 MIMXRT1176xxxxx_cm7_flexspi_nor.icf,全部的 readonly 段分配在 0x30000000 - 0x30FBFFFF 空間(在 Flash 中),全部的 readwrite 段分配在 0x20000000 - 0x2003FFFF 空間(在 DTCM 中)。
3.1 試驗:將 readonly 放入 initialize by copy 中
先來做第一個實驗,不用 except 語法,就是將 readonly 也放入 initialize by copy 中,看看是不是能夠將 APP 中全部程式碼重定向到 DTCM。
編譯連結後,開啟 map 檔案,可以看到 Flash 地址空間內僅剩下 section .boot_hdr.conf 和 .boot_hdr.ivt(這兩個段沒被重定向,主要原因是連結檔案裡沒有用 readonly 修飾) 以及和 IAR 底層函式複製動作相關的原始檔函式(這裡可以便於我們識別哪些函式是和初始化階段複製動作相關的)。
這個結果表明,即使不顯式地寫出 except 語句,那些和複製動作相關的函式也會自動從 readonly 段裡被挑出來,不受 initialize by copy 的影響。
3.2 試驗:用 except 挑出 RT 啟動頭
上一個測試結果在 i.MXRT 下並不能正常工作,除了沒有將 .boot_hdr.xxx 啟動頭全部放在 Flash 指定偏移處之外(兩個沒加 readonly 修飾的僥倖放對了),ARM 中斷向量表也沒有放在指定位置,會影響復位函式 Reset_Handler 的正常執行,因此在 i.MXRT 上我們至少應該將如下段放進 except 列表裡:
編譯連結後,這時候啟動頭以及中斷向量表就被保留在 Flash 指定偏移處了,這個程式下載進 Flash 是可以被晶片正常啟動執行的。
3.3 試驗:用 except 挑出指定原始檔
此時終於進入到客戶需求實現階段了,將需要被保留在 Flash 執行的原始檔/函式全部列出備用。以 hello_world 工程為例,我們就將 hello_world.c 原始檔裡的程式碼全部保留在 Flash 裡,這時候只需要將其加進 except 列表裡即可:
編譯連結後,可以看到 hello_world.o 裡的 ro code 和 const data 均被顯式地保留在 Flash 區域了,客戶需求得以完美實現。
四、如何重定向到非RW段所在RAM?
前面藉助 IAR 特性實現的程式碼重定向均是將程式碼放到 RW 段所在 RAM 區(DTCM),但是對於 i.MX RT 這樣包含多個非連續 RAM 空間的晶片來說,如果客戶希望是重定向到非 RW 段所在的 RAM 空間的話,那情況就大不同了。
關於將 APP 工程裡一些原始檔重定向到任意指定的 RAM,由於 IAR 自身的限制,痞子衡寫過兩篇文章 《在IAR下將整個原始檔程式碼重定向到任意RAM中的方法》、《在IAR下手動複製自定義程式段到RAM中執行的方法》 介紹過實現方法,就是需要在相應程式碼裡增加一些自定義段修飾,但是這種方法顯然不適用客戶這種需求(同樣是因為手工活太多比較繁瑣的原因)。
那這種需求該如何實現呢?這裡留下一個思路,可以結合 IAR 的使用者程式碼庫製作,將無需重定向的程式碼之外的全部程式碼彙編成一個庫(Lib),然後對這個 Lib 整體再進行重定向,思路僅供參考。
至此,在IAR開發環境下將盡可能多的程式碼重定向到RAM中執行的方法痞子衡便介紹完畢了,掌聲在哪裡~~~
歡迎訂閱
文章會同時釋出到我的 部落格園主頁、CSDN主頁、知乎主頁、微信公眾號 平臺上。
微信搜尋"痞子衡嵌入式"或者掃描下面二維碼,就可以在手機上第一時間看了哦。