嵌入式系統/記憶體
在嵌入式系統中,記憶體非常寶貴。某些晶片,特別是嵌入式 VLSI 晶片和低端微處理器可能只有少量的 RAM “板載”(直接內建到晶片中),因此它們的記憶體不可擴充套件。其他嵌入式系統擁有固定數量的記憶體,並且沒有擴充套件手段。除了 RAM 之外,一些嵌入式系統還具有一些非易失性記憶體,例如微型磁碟、FLASH 記憶體擴充套件,甚至各種第三方記憶體卡擴充套件。然而,請記住,嵌入式系統的記憶體升級成本可能高於整個系統本身。因此,嵌入式系統程式設計師需要非常清楚地瞭解可用的記憶體和完成任務所需的記憶體。
記憶體通常被分割成許多不同的區域,這些區域被預留用於特定目的。
通常有 4 個不同的可定址區域,每個區域都使用不同的技術實現
- 程式記憶體(用於儲存你編寫的程式),通常稱為 ROM(儘管大多數開發者更喜歡使用實際上用 Flash 實現此功能的晶片)。在你的程式執行時,無法更改程式記憶體中的任何資料。但至少當電源恢復時,它仍然存在。
- RAM,用於儲存變數和堆疊。(變數的初始值從 ROM 複製)。當電源丟失時,它會忘記所有內容。
- EEPROM。類似於個人計算機中的硬碟驅動器,用於儲存可能偶爾會更改的設定,並且需要在下次啟動時記住。
- I/O。這實際上是微控制器的全部意義所在。
許多流行的微控制器(包括 8051、Atmel AVR、Microchip PIC、Cypress PSoC)具有“哈佛架構”,這意味著程式只能從“ROM”執行。你可以將位元組從 ROM(或其他地方)複製到 RAM,但實際上不可能跳轉或呼叫 RAM 中的這種“程式碼”。這與臺式計算機的情況完全相反,在臺式計算機中,你編寫的程式碼只有在複製到 RAM 中之後才能執行。
一些流行的微控制器(如 68HC11 和 68HC12 等)具有統一的地址空間(“馮·諾依曼架構”)。你可以跳轉或呼叫任何地方的程式碼(儘管跳轉到 I/O 空間中的地址幾乎肯定不是你真正想做的)。
軟體應用程式通常會越來越大。古老的處理器(如火星探測器 Sojourner 上使用的 8085)具有 16 位地址暫存器,可以訪問的最大地址為 65 536 個位置,但是,使用這些處理器的系統通常擁有比這多得多的物理 RAM 和 ROM。它們使用“分頁”硬體將“記憶體塊”進出直接可訪問的空間。早期 Microchip PIC 處理器有兩組完全獨立的“銀行暫存器”,一組用於切換程式 ROM 的不同記憶體塊,另一組用於切換 RAM 的不同記憶體塊。
嵌入式系統編寫的程式經常會越來越大,直到它們超過可用的程式空間。有一些技術[1] 用於處理記憶體不足問題
- 使用“-Os”(最佳化大小)選項重新編譯
- 查詢並註釋掉“死程式碼”
- 將重複部分“重構”到一個公共子程式中
- 用 RAM 空間換取程式空間。
- 在“內部程式記憶體”中放置一個小型直譯器,用於載入和解釋“指令”。
- 使用比直接用匯編語言編碼更緊湊的“指令”,例如 p 程式碼或執行緒程式碼。或者
- 這些“指令”可以放置在 EEPROM 或外部序列 Flash 中,這些 Flash 無法用作程式記憶體。或者
- 兩者兼而有之。這種技術通常用於“郵票”式 CPU 模組中。
- 新增更多記憶體(可能使用分頁或銀行機制)
大多數用於臺式計算機的 CPU 都有一個“記憶體管理單元”(MMU)。MMU 處理虛擬記憶體,保護作業系統使用的記憶體區域免受不受信任的程式的訪問,並且...
大多數嵌入式系統沒有 MMU。我們在嵌入式系統/Linux中討論了可以在沒有 MMU 的系統上執行的兩種 Linux 版本。
保留記憶體是為某些目的預留的記憶體,例如額外的軟體安裝和啟動。
舊的 X86 處理器只有 16 位處理器,如果使用平面記憶體方案,這些處理器將只能支援 65 KB 的記憶體。舊的 8086 和 80286 處理器背後的系統工程師提出了對記憶體進行分段的想法,並使用段暫存器和偏移暫存器的組合來訪問有效的 20 位地址範圍,最多可以訪問 1 MB 的記憶體。
地址 = (段暫存器 * 16) + 指標暫存器
新的 32 位處理器允許 4 GB 的可定址記憶體空間,因此分段記憶體模型在當前的 32 位機器中幾乎被放棄(儘管段暫存器仍然用於實現分頁方案)。
記憶體對映 I/O 是一種機制,透過該機制,處理器使用記憶體訪問技術執行 I/O 訪問。這通常是透過實現的,因為記憶體匯流排通常比 I/O 匯流排快得多。記憶體對映 I/O 可能被使用的另一個原因是使用的體系結構沒有單獨的 I/O 匯流排。
在記憶體對映 I/O 中,CPU 地址空間的某些範圍被預留給外部外設。可以使用與其他記憶體訪問相同的指令訪問這些位置。但是,對這些地址的讀/寫被解釋為對裝置的訪問,而不是對主記憶體中的位置的訪問。
CPU 可能期望某個特定裝置位於固定位置,或者可以動態分配空間供它使用。
這種工作方式是記憶體介面通常被設計成匯流排(一種共享的通訊資源),其中連線了多個裝置。這些裝置通常被排列為主裝置和從裝置,主裝置可以向任何從裝置傳送和接收資料。一個典型的系統會有
- CPU 作為主裝置
- 一個或多個 RAM 和/或 ROM 裝置用於程式程式碼和資料儲存
- 外圍裝置用於與外部世界互動。這些裝置的例子可能包括 UART(序列通訊)、顯示裝置或輸入裝置
進一步閱讀
[edit | edit source]一些流行的小型系統直譯器(其中一些我們在前面簡要提及過)包括
- Forth; 一個 Forth wiki 列出了許多 Forth 移植到嵌入式系統的版本。
- (一個子集) Python
- (一個子集) BASIC 程式設計,通常是標記化的 BASIC,例如 PBASIC 或 PICAXE BASIC
- 維基百科:CHIP-8
- 維基百科:XPL0
- (一個子集) Lua 函數語言程式設計 ([1])
- (一個子集) Objective Caml ([2])
- (一個子集) 嵌入式系統/C 程式設計,一個 C 直譯器,例如 PicoC 或 維基百科:互動式 C。
- "在微型記憶體中執行的互動式語言有哪些?" 在 Stack Overflow 上