大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家分享的是IAR下手動拷貝自定義程式段到RAM中執行的方法。 在痞子衡舊文 《IAR下RT-Thread工程自定義函數段重定向失效分析》 里,我們知道 IAR 鏈接器處理自定義程式段重定向是有一些限制的,只要用戶重寫了底層 __low_level ...
大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家分享的是IAR下手動拷貝自定義程式段到RAM中執行的方法。
在痞子衡舊文 《IAR下RT-Thread工程自定義函數段重定向失效分析》 里,我們知道 IAR 鏈接器處理自定義程式段重定向是有一些限制的,只要用戶重寫了底層 __low_level_init() 函數,那麼這個函數里不能調用任何與自定義程式段相關的代碼,否則自定義程式段就不會被 IAR 鏈接器(initialize by copy)正常處理。這其實對用戶來說不太友好,既然如此,我們乾脆就不用 IAR 鏈接器來做代碼重定向了,今天痞子衡教大家手動拷貝程式段到 RAM 中的方法。
手動拷貝自定義程式段除瞭解決 IAR 鏈接器限制之外,還有另外一個用處,那就是拷貝的位置可以由用戶決定。比如我們希望將程式重定向到外部 PSRAM 執行,但是在拷貝之前是需要先初始化外部 PSRAM 的,這時候我們完全可以在 main 函數里做完 PSRAM 初始化之後再做程式段的拷貝。
- Note 1: 閱讀本文前需要對 《IAR鏈接文件(.icf)》、《IAR映射文件(.map)》 這兩種文件有所瞭解。
- Note 2: 本文使用的 IAR EWARM 軟體版本是 v9.30.1。
一、源文件里自定義程式段
首先我們要將需要重定向到 RAM 中執行的全部關鍵函數放到同一個自定義程式段里,具體方法參見痞子衡舊文 《在IAR下將關鍵函數重定向到RAM中執行的方法》 里 2.2 小節。
我們以最經典的 \SDK_2.13.1_MIMXRT1170-EVK\boards\evkmimxrt1170\demo_apps\hello_world\cm7\iar 常式( flexspi_nor_debug build)為例,將其 SysTick_DelayTicks() 函數放到自定義程式段 UserRelocateCode 里,寫法如下:
#pragma location = "UserRelocateCode"
void SysTick_DelayTicks(uint32_t n)
{
g_systickCounter = n;
while (g_systickCounter != 0U)
{
}
}
二、鏈接文件里處理自定義程式段
有了自定義程式段 UserRelocateCode 後,現在我們需要告訴 IAR 鏈接器,這個程式段將由用戶自己做初始化處理。打開工程鏈接文件 MIMXRT1176xxxxx_cm7_flexspi_nor.icf 添加如下語句。即將 UserRelocateCode 段重定向到 EXTRAM_region 里執行,並且這裡最關鍵的是 initialize manually 這一句(區別於 SDK CodeQuickAccess 段重定向做法所用的 initialize by copy)。
define symbol m_external_ram_start = 0x60000000;
define symbol m_external_ram_end = 0x6003FFFF;
define region EXTRAM_region = mem:[from m_external_ram_start to m_external_ram_end];
initialize manually { section UserRelocateCode };
place in EXTRAM_region { section UserRelocateCode };
編譯修改後的工程,查看其映射文件(.map),其中和 UserRelocateCode 段相關的內容如下,這裡可以看到除了 P10 之外,P1 里還多了一個名為 UserRelocateCode_init 的段,這其實就是自定義程式段機器碼在 Flash 里的存放位置(拷貝數據源)。
*******************************************************************************
*** PLACEMENT SUMMARY
***
"P10": place in [from 0x6000'0000 to 0x6003'ffff] { section UserRelocateCode };
initialize manually with packing = none { section UserRelocateCode };
Section Kind Address Size Object
------- ---- ------- ---- ------
"P1": 0x4738
UserRelocateCode_init 0x3000'6800 0x10 <Block>
Initializer bytes const 0x3000'6800 0x10 <for UserRelocateCode-1>
"P10": 0x10
UserRelocateCode 0x6000'0000 0x10 <Block>
UserRelocateCode-1 0x6000'0000 0x10 <Init block>
UserRelocateCode inited 0x6000'0000 0x10 led_blinky.o [7]
- 0x6000'0010 0x10
三、手動拷貝自定義程式段
上一節我們在映射文件里看到 UserRelocateCode_init 段的出現,這其實 IAR 的預設規定,可在 \IAR Systems\Embedded Workbench 9.30.1\arm\doc\EWARM_DevelopmentGuide.ENU.pdf 文檔找到相應規則,即重定向的自定義段,其初始化值將被放到名為原自定義段名 + _init 尾碼的段里。
一切準備就緒,拷貝代碼的實現還是比較簡單的,下麵是示例拷貝函數 user_code_init()。有了它,我們就可以在 main 函數里自由決定其調用位置了。
#pragma section = "UserRelocateCode"
#pragma section = "UserRelocateCode_init"
void user_code_init(void)
{
uint8_t *dest_start, *src_start, *src_end;
uint32_t codebytes;
dest_start = __section_begin("UserRelocateCode");
src_start = __section_begin("UserRelocateCode_init");
src_end = __section_end("UserRelocateCode_init");
codebytes = src_end - src_start;
while (codebytes--)
{
*dest_start++ = *src_start++;
}
}
int main(void)
{
psram_init();
user_code_init();
// 代碼省略...
}
至此,IAR下手動拷貝自定義程式段到RAM中執行的方法痞子衡便介紹完畢了,掌聲在哪裡~~~
歡迎訂閱
文章會同時發佈到我的 博客園主頁、CSDN主頁、知乎主頁、微信公眾號 平臺上。
微信搜索"痞子衡嵌入式"或者掃描下麵二維碼,就可以在手機上第一時間看了哦。
最後歡迎關註痞子衡個人微信公眾號【痞子衡嵌入式】,一個專註嵌入式技術的公眾號,跟著痞子衡一起玩轉嵌入式。
衡傑(痞子衡),目前就職於某知名外企半導體公司MCU系統部門,擔任嵌入式系統應用工程師。
專欄內所有文章的轉載請註明出處:http://www.cnblogs.com/henjay724/
與痞子衡進一步交流或咨詢業務合作請發郵件至 [email protected]
可以關註痞子衡的Github主頁 https://github.com/JayHeng,有很多好玩的嵌入式項目。
關於專欄文章有任何疑問請直接在博客下麵留言,痞子衡會及時回覆免費(劃重點)答疑。
痞子衡郵箱已被私信擠爆,技術問題不推薦私信,堅持私信請先掃碼付款(5元起步)再發。