大多數現代嵌入式軟體應用都是從Flash(Flash)存取和執行的。Flash為基於微控制器(MCU)的應用提供了便宜且快速的儲存介質。這些應用通常都是即時的,對執行時間和確定性行為有嚴格要求。雖然Flash速度已經很快,但還是不如從RAM執行程式碼那麼快。為了加快基於Flash的應用執行時間,開發人員可以選擇一些關鍵功能從RAM執行,以獲得額外的速度提升。

為了從RAM執行一項功能,開發人員通常需要遵循三個步驟,包括:

  1. 在功能連結器中創建RAM區域
  2. 指定哪些功能應儲存在RAM
  3. 在啟動時將這些功能複製到RAM

讓我們詳細探討一下這個過程。

步驟#1:在功能連結器中創建RAM區域

每個編譯器都使用不同的語法來定義MCU內的儲存區域。對於本文的示例,我們將使用基於GCC的Code Composer Studio以及與TI C2000系列一起使用的語法,我相信它可以提供一個很好的例子。

當我們修改連結器檔以包含將從RAM執行的功能時,需要創建一個記憶體單元來指定功能將從哪裡載入到RAM,以及將載入到RAM中哪個位置。

連結器檔將包含指定重要程式分配的區域,例如:

  • cinit
  • text
  • codestart
  • stack
  • constants

開發人員需要為其RAM功能創建一個區域,可以使用以下程式碼完成: 20181228_Flash_TA01T1

如你所見,這是在RAM中創建一個名為ramfuncs的區域。RAM區域將儲存在FLASH A磁區的功能載入,它被指定在RAM區RAML0中運行。然後有一些定義用於指定RAM功能的開始和結束位置以及它們的大小。這些值在步驟#3中就顯出重要性了。

步驟#2:指定哪些功能應儲存在RAM

一旦在連結器中創建了一個RAM區域來儲存指定的功能,我們需要指定功能應該駐留其中的連結器。最常用於執行此操作的方法是使用#pragma。通常,我們應該儘量避免在程式碼中使用#pragma,因為它是依賴於編譯器的。這意味著如果編譯器發生改變,開發人員很可能就必須修改#pragma行。對於我們要達到的目的,這沒關係,因為我們無論如何都必須修改一個新的連結器檔,我們需要找出正確的語法來指定如何將一個功能放入記憶體區域。

通常從RAM執行的一組通用功能是與存取和控制Flash相關的功能。原因是當我們想要寫入或擦除Flash時,大多數MCU都不允許同時執行Flash程式碼!因此,無論如何我們需要將這些功能放入RAM中。我們可以使用類似如下的程式碼將Flash_Init等功能放入RAM區域:

20181228_Flash_TA01T2

你可以從這一語句中看到我們正在使用自訂編譯器標識CODE_SECTION來指定Flash_Init功能應放入連結器中的ramfuncs區域。該語句通常應該直接放在功能定義的上方,以提示任何操作該功能的開發人員要將它放到RAM中。 (這也使我們更容易找到它,如果我們認為該功能不需要放在RAM中的話)。

步驟#3:在啟動時將功能複製到RAM

該過程的最後一步是確保在微控制器啟動期間將我們想要在RAM中執行的功能真正被複製到RAM中。最簡單的方法是使用memcpy。我通常在配置系統時脈和中斷向量表之後執行這一複製操作,但要在初始化板載週邊和應用程式碼之前。我在步驟#1中提到過,我們定義的幾個變數會在以後派上用場。它們是RamfuncsRunStart、RamfuncsLoadStart和RamfuncsLoadSize。我們將使用memcpy和這些變數將功能複製到RAM中,按照以下語句:

20181228_Flash_TA01T3

就這麼簡單。完成後,開發人員只需簡單調用功能,就像通常那樣,該功能就可以在RAM中執行。

總結

總之,當開發人員從Flash執行應用程式碼時,他們可以將這些功能複製到RAM中,以加速執行程式碼的關鍵部份。從RAM執行一個功能將透過消除可能與從Flash存取指令相關的任何等候狀態來提高執行速度。這種額外的提升可確保關鍵功能以盡可能快的速度執行。正如我們所看到的,一旦你操作一兩次後,就會發現將功能載入到RAM中並執行其實非常簡單。

(參考原文:Speeding up flash-based embedded applications,by Jacob Beningo)