大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家分享的是IAR環境下無法直接下載除錯i.MXRT分散連結工程的解決方案。
分散連結與載入一直是嵌入式領域比較勸退新手的難題,在恩智浦 i.MXRT 系列為代表的多儲存器架構的 MCU 上,分散連結問題體現得尤為明顯,畢竟你在連結應用程式各種段(section)時可能會面對包括內部 ITCM/DTCM/OCRAM 和外部 Flash/SDRAM/PSRAM/HyperRAM 等多種儲存器空間選擇。
雖然儲存器空間選擇很多,但是一個最終可離線啟動的 i.MXRT 程式(即能被下載進外部非易失儲存器,且能被 BootROM 載入啟動)其 readonly 段應該是一段連續的資料(SREC/HEX格式映象檔案裡僅能包含一段空間地址),即要連結在一個主儲存器空間裡,這也意味著其它連結在非主儲存器空間的 .text 段應該使用重定向方法來實現,不可直接原地連結,參考痞子衡文章 《IAR下將原始檔程式碼重定向到任意RAM中的方法》。
最近有一個 i.MXRT1060 客戶,他們就遇到了分散連結工程除錯問題,工程 readonly 段被直接分散連結到了兩個不同的外部儲存器空間,沒有用重定向方法,這雖然不符合離線啟動要求,但是在 IAR 下直接下載除錯也會報錯,這是怎麼回事?
一、引出客戶問題
我們再進一步描述客戶工程分散連結問題,下圖包含了 i.MXRT 架構下程式段的全部連結選擇,根據這些選擇組合,我們能產生多種不同的工程連結檔案。
先來看不涉及分散連結的簡單情況,即 readonly 段全在 Flash 裡,readwrite 段在一個或多個 RAM 空間裡,這種情況下 IAR 下載除錯沒有什麼特殊注意事項,flashloader 會負責外部 Flash 初始化,並將 readonly 段資料下載進 Flash,然後巨集檔案負責外部 RAM 初始化,線上除錯一切正常。
Case1: APP readonly text/data1 + APP readwrite data2/3/4
再來看第二種情況,這裡開始涉及分散連結,readonly 段分散在多個 RAM 空間,readwrite 段在一個或多個 RAM 空間裡。這種情況下因為沒有連結在 Flash 空間,因此無需 flashloader,完全由巨集檔案將相關外部 RAM 初始化好,多個 readonly 段都能正常下載,線上除錯一切正常。
Case2: APP readonly text/data2/3/4 + APP readonly text/data2/3/4 + APP readwrite data2/3/4
第三種情況再複雜一點,readonly 段除了在 Flash 空間外,還有一部分放在了內部 RAM 裡,然後 readwrite 段依然在一個或多個 RAM 空間裡。這種情況下 IAR 下載除錯感覺上應該沒問題,因為內部 RAM 無需初始化可直接訪問,兩個不連續 readonly 段原則上可以下載,但是很遺憾,IAR 會報錯,其 flashloader 無法處理放在內部 RAM 的 readonly 段,除錯無法進行。
Case3: APP readonly text/data1 + APP readonly text/data2 + APP readwrite data2/3/4
最後一種分散連結的情況最複雜,也是客戶的問題所在,readonly 段除了在 Flash 空間外,還有一部分放在了外部 RAM,然後 readwrite 段在一個或多個 RAM 空間裡。這種情況下 IAR 下載除錯一定會出問題,預設 flashloader 只做了 Flash 初始化,並不負責初始化外部 RAM,因此部分 readonly 段往外部 RAM 下載時會報錯,工程巨集檔案雖然負責初始化外部 RAM,但其執行階段在 flashloader 作用之後,鞭長莫及。
Case4: APP readonly text/data1 + APP readonly text/data3/4 + APP readwrite data2/3/4
二、復現客戶問題
我們在恩智浦官方 MIMXRT1060-EVK 板上覆現一下客戶問題,使用 \SDK_2.11.0_EVK-MIMXRT1060\boards\evkmimxrt1060\demo_apps\hello_world\iar 工程,原工程有很多 Build,我們就選用 flexspi_nor_sdram build,它用到了兩塊外部儲存器,符合客戶場景。在這個 build 裡 readonly 段都鏈在外部 Flash 裡,readwrite 段都連結在外部 SDRAM 裡,顯然這個情況屬於第一節介紹的 case1:
1. Flash初始化工作:\IAR Systems\Embedded Workbench 9.10.2\arm\config\flashloader\NXP\FlashIMXRT1060_FlexSPI.out
2. SDRAM初始化工作:\SDK_2.11.0_EVK-MIMXRT1060\boards\evkmimxrt1060\demo_apps\hello_world\iar\evkmimxrt1060_sdram_init.mac
我們現在要將工程稍微改動一下,在工程原始檔裡定義一個 sw_delay() 函式(記得要在 main 函式裡呼叫一下),並且將其指定在自定義 .sdramCodeSection 段裡:
#pragma default_function_attributes = @ ".sdramCodeSection"
void sw_delay(void)
{
__NOP();
}
#pragma default_function_attributes =
然後在工程連結檔案裡將這個自定義 .sdramCodeSection 段放到 SDRAM 空間裡,這樣我們在外部 Flash 和 SDRAM 空間裡就都有 readonly 段了,跟客戶情況一致了。
place in DATA3_region { section .sdramCodeSection };
板卡上電,直接用板載 DAP-Link 偵錯程式線上下載工程(為了減少對板子設定的依賴,我們將偵錯程式復位型別改為 Core),下載過程中 IAR 果然一直在報錯,如果你忽略錯誤繼續除錯,雖然斷點會停在 main 函式,但是隻要單步進放到 SDRAM 空間的函式裡時,程式就會跑飛進 hardfault,因為 SDRAM 中根本就沒有正確的 .sdramCodeSection 段資料。
三、嘗試僅藉助巨集檔案(.mac)解決問題
分析到這裡,其實你應該知道問題出在哪裡了,工程配套巨集檔案 evkmimxrt1060_sdram_init.mac 本應負責 SDRAM 初始化,但是其執行順序在 FlashIMXRT1060_FlexSPI.out 作用之後,所以沒有產生其該有的效果,這個具體可見痞子衡舊文 《IAR內部C-SPY除錯元件配套巨集檔案(.mac)用法介紹》 3.1 小節,有非常詳細的解釋。
現在的解決思路就是,如何讓 evkmimxrt1060_sdram_init.mac 裡的 SDRAM 初始化語句在 flashloader 作用之前生效,所以我們很自然地想在 flashloader 配套的巨集檔案 FlashIMXRT1060_FlexSPI.mac 裡的 execUserFlashInit() 介面裡將 SDRAM 初始化語句都加上,但是很遺憾,這招不湊效,其實在第一節介紹的 case3 裡就應該認清現實了,內部 RAM 無需初始化 IAR 也無法正常下載。
四、藉助雙Flashloader解決問題
其實 IAR 軟體設計裡,對於兩個 readonly 段,只要其中有一個段被放入了 Flash 裡(即需要 flashloader),那麼另外一個段不管是不是放在 Flash 裡也需要有相應 flashloader,這裡痞子衡要吐槽下 IAR 的設計,有點呆板了。
所以本文案例裡解決問題的關鍵就是為 SDRAM 也設計一個 flashloader,具體制作方法可以參考痞子衡舊文 《序列NOR Flash下載演算法(IAR EWARM篇)》。因為 SDRAM 擦寫其實也不需要什麼特殊命令時序,就是單純 AHB 方式地寫就行了,所以這個 SDRAM 版本的 flashloader 就是個傀儡 flashloader 而已。
痞子衡為了讓這個傀儡 flashloader 更通用一些,是按如下方式實現三個主要 flashloader API 的,其中 FlashInit() 函式裡故意沒有加 SEMC 模組初始化程式碼,就是為了讓這個 flashloader 適用所有型別的 RAM(ITCM/DTCM/OCRAM/SDRAM/PSRAM/HyperRAM),外設初始化工作放在傀儡 flashloader 配套巨集檔案裡去完成。
FlashInit() - 什麼都不做,直接返回
FlashWrite() - 用 memcpy 函式實現
FlashErase() - 用 memset 函式實現
最終 RAM 型通用 flashloader 原始碼工程地址如下:
https://github.com/JayHeng/imxrt-tool-flash-algo/tree/master/boards/nxp_evkmimxrt1060_rev.a1/ram_algo/IAR
我們把新生成的 SDRAM flashloader 相關的所有檔案(.out/.flash/.mac)放到對應 IAR 系統目錄下,並且修改原來的 FlashIMXRT1060_EVK_FlexSPI.board 檔案,加入 SDRAM 相關的部分:
1. FlashIMXRT1060_SEMC.mac 檔案基本沿用 evkmimxrt1060_sdram_init.mac 檔案,只是 setup 巨集函式從 execUserPreload 換到 execUserFlashInit
2. FlashIMXRT1060_SEMC.flash 檔案內容按 FlashIMXRT1060_FlexSPI1.flash 寫即可,注意檔案字尾一定要是 .flash, IAR 只認這個字尾。
現在再去下載除錯,就一切正常了,說明雙 Flashloader 解決方案生效了。本例是以 IAR flashloader 為例的,如果用 J-Link flashloader 也是可以的,一樣的原理製作兩個 Flashloader 即可。
至此,IAR環境下無法直接下載除錯i.MXRT分散連結工程的解決方案痞子衡便介紹完畢了,掌聲在哪裡~~~
歡迎訂閱
文章會同時釋出到我的 部落格園主頁、CSDN主頁、知乎主頁、微信公眾號 平臺上。
微信搜尋"痞子衡嵌入式"或者掃描下面二維碼,就可以在手機上第一時間看了哦。