痞子衡嵌入式:在IAR開發環境下手動拷貝自定義程式段到RAM中執行的方法

2023-11-20 21:00:22

  大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家分享的是IAR下手動拷貝自定義程式段到RAM中執行的方法

  在痞子衡舊文 《IAR下RT-Thread工程自定義函數段重定向失效分析》 裡,我們知道 IAR 連結器處理自定義程式段重定向是有一些限制的,只要使用者重寫了底層 __low_level_init() 函數,那麼這個函數裡不能呼叫任何與自定義程式段相關的程式碼,否則自定義程式段就不會被 IAR 連結器(initialize by copy)正常處理。這其實對使用者來說不太友好,既然如此,我們乾脆就不用 IAR 連結器來做程式碼重定向了,今天痞子衡教大家手動拷貝程式段到 RAM 中的方法。

  手動拷貝自定義程式段除了解決 IAR 連結器限制之外,還有另外一個用處,那就是拷貝的位置可以由使用者決定。比如我們希望將程式重定向到外部 PSRAM 執行,但是在拷貝之前是需要先初始化外部 PSRAM 的,這時候我們完全可以在 main 函數裡做完 PSRAM 初始化之後再做程式段的拷貝。

一、原始檔裡自定義程式段

  首先我們要將需要重定向到 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主頁知乎主頁微信公眾號 平臺上。

微信搜尋"痞子衡嵌入式"或者掃描下面二維條碼,就可以在手機上第一時間看了哦。