ARM Cortex-M底層技術(十)KEIL MDK 分散加載示例2-代碼加載到片內SRAM中運行以及部分規則

 

 KEIL MDK 分散加載示例2-代碼加載到片內SRAM中運行&部分規則

    小編我一向主張在實戰中學習,不主張直接去去學習規則&定義,太枯燥,在實際應用中去摸索,纔會真正理解具體的技術細節,下面我們就通過實際的簡單用例來搞清楚分散加載。   

簡單示例

    這個功能是非常有用的,這個小編我之前的文章提過,是一種可以顯著增加程序運算速度的方法,所以比較常用,可以把核心算法相關的文件分散加載到SRAM區域上去以加快程序運行速度。

    按照上個示例的方式修改分散加載,只是這次我們要把加載域以及RO運行域放到片內SRAM上。代碼加載到SRAM上運行就意味着RO、RW、ZI都要放到SRAM上,這種用法顯然對片內SRAM的大小是一個重大考驗,當然我們的示例比較簡單,重點在於展示用法,我們先來看把所有代碼都加載到片內SRAM上的操作。當然這種用法比較暴力,小編我並不推薦這種玩法,只把對時間要求最高的部分代碼加載到SRAM上纔是真實會經常用到的玩法,這裏我們先來看簡單暴力的:把所有代碼加載到SRAM上的玩法。

LPC824有8KB SRAM,我們簡單點把前4KB作爲程序的加載域以及RO運行域,後4KB作爲RW+ZI的運行域,如下:

    

    修改對應的ini文件,如下:

    

   編譯鏈接,然後我們看一下對應的.map文件(之前文章提過的):

    

   可以看到,除了CRP-KEY(加密位)以外的所有代碼包括__main都被加載到了0x10000000起始的地址上。對比一下沒改之前的,注意地址的變化:

    跑一下程序,完美運行。

上面示例存在的問題

    上面示例有一個致命問題,導致其完全無法在實際中使用,細心的童鞋估計看粗來了,代碼的加載域在SRAM上,而SRAM的數據掉電就會丟失,

使得上面的這個玩法完全不具備實用性,那麼讓加載域在Flash上,RO執行域在SRAM這樣再不同的地址空間上可行嗎?我們試一試:

    如上:很簡單,加載域在Flash上,RO運行域在片內SRAM上的前4KB空間上,RW+ZI運行域在後4KB的SRAM上,它既解決了上面那個示例掉

電的問題,又解決了運行速度問題。

關鍵是能運行嗎?編譯&鏈接看看?

    如上:鏈接器不幹了,一火車皮的錯誤,最多的提示是“non-root region xxxxxx”這是啥????

WHY??

    把代碼放到Flash上存儲,解決掉電問題,運行放在SRAM上解決速度問題。但上面的分散加載呢?加載域的起始地址是Flash的起始地址,運行

域的起始地址是SRAM上,看似跟我們的分散加載描述具備一致性,但爲什麼不行呢?

    原因在於分散加載本身不能被分散加載,好繞口,啥意思?比如你拍照(只有一臺相機),但是你卻想把自己的相機也拍到照片裏面,這顯然是

做不到的。分散加載也一樣,它是一段在__main()中的代碼(之前啓動代碼部分文章多次提過),這段代碼會被一起燒寫到MCU裏面,把各個數據

段搬到指定的位置上也是由分散加載來執行的,但我們再仔細看一下這個分散加載:

LR_IROM1 0x00000000 0x00008000  {    ; load region size_region

  ER_IROM1 0x10000000 0x00001000  {  ; load address = execution address
        xxxx
  }
  RW_IRAM1 0x10001000 0x00001000  {  ; RW data
        xxxx
  }

}

    所有的RO執行域都被放到了0x10000000起始大小爲0x1000的地址上面了,這個工作顯然是要分散加載來做的,但是分散加載本身又在起始地

址爲0x10000000大小爲0x1000的這個本身就需要被分散加載的空間上了,這就是矛盾!也就是分散加載本身不能被分散加載的意思了(分散加載

受到的一個限制是負責創建執行區的代碼和數據不能將自己複製到另一個位置)。所以在Keil的分散加載中,第一個RO運行域必須與加載域基地址

相同。用這種方法來確保分散加載可以被正確的找到以及執行。

修改一下再運行看看

    瞭解了問題原因,我們再修改下上面的示例:

    

    如上示例中,我們強制性的把RO運行域中分散加載的代碼段放到了第一個RO運行域中而且起始地址與加載域一致。用戶代碼的RO段我們放到S

 

RAM上,我們編譯鏈接看一下。這裏就直接說結論,編譯鏈接可以過,但是運行之後程序會死在__main裏面,WHY????

    

    原因是這樣的,ER_IROM2這個RO執行域是在程序運行起來之後再分散加載到SRAM上面的,辣麼也就是要向加載域裏面寫數據,這顯然是不行

 

的,所以我們需要如下修改:

    DEBUG,程序完美運行。    

“InRoot$$Sections”與“根區”的說明:   

    我們到現在爲止看到了許多分散加載都有“InRoot$$Sections”這個節,這是啥東東呢?

    我們上面提到過分散加載受到的一個限制是負責創建執行區的代碼和數據不能將自己複製到另一個位置,分散加載需要有一個根區,根區本質是

一個RO執行域,其執行地址與其加載地址相同。    

    根區中需要包含以下幾個節:

    <1>複製代碼和數據的程序代碼,也就是__main.o和__scatter*.o(__scatter.o、__scatter_copy.o、__scatter_zi.o等)

    <2>執行壓縮的__dc*.o(同樣包含很多以__dc開頭的obj文件)

    <3>Region$$Table節,包含要複製和壓縮的帶麼和數據的地址

    如果要在其他非根區內指定*(+RO)那麼需要使用“InRoot$$Sections”來在根區顯示的指定這些節。

    簡單來說,就是每個分散加載都要有一個根區,根區需要指定“InRoot$$Sections”節或者等效的其他節(簡單來說就是分散加載、__main、數

據壓縮這些東西必須要放到根區)

    這個等效節是指什麼?

    比如在我們的這個簡單示例裏面,不過不用“InRoot$$Sections”來指定根區,那麼如下的編寫方式也是OK的:

    

    不同程序這裏寫法不同,在我們的簡單示例裏面這樣足夠,具體哪些部分要放到根區裏面,可以直接去看.map文件把鏈接到工程中的C Library

的obj文件放進來就可以了,RT以及浮點的部分與之無關。如果你不想這麼麻煩就直接使用“InRoot$$Sections”標號來指定根區也可以。

原文鏈接:https://blog.csdn.net/weixin_39118482/article/details/80162158

發佈了17 篇原創文章 · 獲贊 16 · 訪問量 2455
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章