大多數(shù)現(xiàn)代嵌入式軟件應(yīng)用程序都是從閃存存儲(chǔ)和執(zhí)行的。閃存為基于微控制器的應(yīng)用程序提供了一種廉價(jià)且快速的存儲(chǔ)介質(zhì)。但這些應(yīng)用程序通常是實(shí)時(shí)應(yīng)用程序,其中執(zhí)行時(shí)間和確定性行為至關(guān)重要。雖然閃存速度很快,但不如從RAM執(zhí)行代碼快。為了加快基于flash的應(yīng)用程序的執(zhí)行時(shí)間,嵌入式開發(fā)人員可以有選擇地選擇關(guān)鍵功能并從RAM中執(zhí)行它們,以獲得額外的速度提升。
為了從RAM執(zhí)行功能,開發(fā)人員通常需要遵循三個(gè)步驟。這些措施包括:1.在鏈接器中為函數(shù)創(chuàng)建RAM區(qū)域;2.指定哪些函數(shù)應(yīng)存儲(chǔ)在RAM中;3.啟動(dòng)時(shí)將功能復(fù)制到RAM中。
讓我們詳細(xì)檢查這個(gè)過程。
步驟1–在鏈接器中為函數(shù)創(chuàng)建RAM區(qū)域
每個(gè)編譯器都有不同的語法來定義微控制器中的內(nèi)存區(qū)域。對于今天的示例,我將使用基于GCC的Code Composer
Studio和Texas儀器C2000系列使用的語法,因?yàn)槲艺J(rèn)為它提供了一個(gè)很好的示例。
當(dāng)我們修改鏈接器文件以包含將從RAM執(zhí)行的函數(shù)時(shí),我們需要?jiǎng)?chuàng)建一個(gè)內(nèi)存部分,該部分將指定函數(shù)從何處加載到RAM中,以及該函數(shù)從何處加載到RAM中。鏈接器文件將包含指定重要程序分配的區(qū)域,例如:
cinit
text
codestart
stack
constants
···
嵌入式開發(fā)人員需要為其RAM功能創(chuàng)建一個(gè)區(qū)域。這可以通過以下方法實(shí)現(xiàn):
ramfuncs : LOAD = FLASHA,
RUN = RAML0,
LOAD_START (_RamfuncsLoadStart),
LOAD_END (_RamfuncsLoadEnd),
RUN_START (_RamfuncsRunStart),
LOAD_SIZE (_RamfuncsLoadSize),
PAGE = 0
如你所見,這是在RAM中創(chuàng)建一個(gè)名為ramfuncs的區(qū)域。RAM區(qū)域是從存儲(chǔ)在閃存A扇區(qū)中的函數(shù)加載的。它被指定在RAM區(qū)域RAML0中運(yùn)行。然后有一些定義用于指定RAM函數(shù)的開始和結(jié)束位置以及它們的大小。這些值在步驟#3中很重要。
步驟2–指定哪些函數(shù)應(yīng)存儲(chǔ)在RAM中
一旦我們在鏈接器中創(chuàng)建了一個(gè)RAM部分來存儲(chǔ)我們的函數(shù),我們就需要向鏈接器指定哪些函數(shù)應(yīng)該駐留在那里。最常用的方法是使用#pragma。一般來說,我們應(yīng)該盡量避免在代碼中使用#pragma,因?yàn)檫@些功能依賴于編譯器。這意味著,如果編譯器發(fā)生更改,嵌入式開發(fā)人員很可能不得不修改#pragma行。就我們今天的目的而言,這沒有問題,因?yàn)槲覀儫o論如何都必須修改一個(gè)新的鏈接器文件,并且我們需要找出正確的語法來指定如何在內(nèi)存區(qū)域中放置函數(shù)。
通常從RAM執(zhí)行的一組常見功能是與訪問和控制閃存有關(guān)的功能。原因是當(dāng)我們想要寫入或擦除閃存時(shí),大多數(shù)微控制器不允許你同時(shí)從閃存執(zhí)行代碼!所以,我們無論如何都需要把這些函數(shù)放到RAM中。我們可以使用類似于以下代碼的代碼將諸如Flash_Init之類的函數(shù)放入RAM區(qū)域:
#pragma CODE_SECTION(Flash_Init, “ramfuncs”);
從該語句中可以看出,我們正在使用自定義編譯器指定代碼_部分來指定函數(shù)Flash_Init應(yīng)放置在鏈接器的ramfuncs區(qū)域中。此語句通常直接放在函數(shù)定義的上方,以提醒任何處理函數(shù)的開發(fā)人員它將被放入RAM中。(這也使得我們更容易找到是否應(yīng)該決定函數(shù)不需要放在RAM中)。
步驟3–啟動(dòng)時(shí)將功能復(fù)制到RAM中
該過程的最后一步是確保在微控制器啟動(dòng)期間,我們想要在RAM中執(zhí)行的功能實(shí)際上被復(fù)制到RAM中。最簡單的方法是使用memcpy。我通常在配置系統(tǒng)時(shí)鐘和中斷向量表后不久,但在初始化板載外圍設(shè)備和應(yīng)用程序代碼之前,執(zhí)行此復(fù)制。我在步驟1中提到,我們定義了幾個(gè)變量,這些變量稍后會(huì)派上用場。這些是RamfuncsRunStart、RamfuncsLoadStart和RamfuncsLoadSize。我們將使用以下語句將這些函數(shù)與memcpy一起復(fù)制到RAM中:
memcpy(&RamfuncsRunStart, &RamfuncsLoadStart,
(Uint32)&RamfuncsLoadSize);
就這么簡單。一旦這樣做了,開發(fā)人員只需像平常一樣調(diào)用函數(shù),函數(shù)在RAM中執(zhí)行。
結(jié)論
當(dāng)嵌入式開發(fā)人員從flash執(zhí)行應(yīng)用程序代碼時(shí),他們可以通過將這些函數(shù)復(fù)制到RAM中來加速代碼的關(guān)鍵部分。從RAM執(zhí)行功能將通過移除可能與從閃存訪問和加載指令相關(guān)的任何等待狀態(tài)來提高執(zhí)行速度。這種額外的提升可以確保關(guān)鍵功能能夠以盡可能快的速度執(zhí)行。正如我們所看到的,將函數(shù)加載到RAM中并執(zhí)行它們是簡單而直接的(只要你做了一兩次)。