開發人員喜歡相信運行他們軟件的微處理器會忠實地遵循他們創建的程序流程,并按照預期無限期地運行。事實是,有時事情會出錯,程序會被忽略。出現這種情況有許多可能的原因,例如覆蓋了數組的邊界,在初始化之前使用了指針,或者許多其他可能的原因。當發生這種情況時,嵌入式開發人員恢復系統的最有用的技術之一是用可以捕獲故障的東西來填充未使用的內存。
有多種可能性可以填充未使用的內存。第一個是重置向量位置。如果事情出了差錯,CPU將加載重置向量,程序將從頭開始。這將更像是應用程序的一種軟的、不受控制的終止,幾乎沒有關于原因的調試信息。硬件將處于不確定狀態,無法保證系統能從復位狀態中正常恢復。
第二種可能更合適的行為是將一個已知的中斷向量放在空內存中。在這種情況下,當事情變得非常糟糕時,應用程序有機會捕獲事件并提供一些線索,如CPU寄存器狀態,以了解發生了什么。這使得開發人員可以重現和調試原因,而不是盲目猜測。
如果對調試信息不感興趣,可以使用的第三種選擇是用暫停或轉移到自身指令來填充存儲器。這將具有停止微控制器運行的效果。這種技術的優點是防止微控制器失控并繼續錯誤地執行代碼。相反,一切都停止了,值得信賴的看門狗定時器(每個嵌入式開發人員都會啟用,我希望如此)通過超時和執行系統硬復位來拯救我們。
最后一個不推薦的選擇是用胡言亂語填充內存。選擇一個位模式,如0x55、0xAA、0xAA55,并期待最好的結果。在這種情況下,填充存儲器實際上并不是為了提高應用程序的健壯性,而是為了提供除0xFF之外的已知值,以便執行ROM校驗和。在網上簡單搜索一下就發現了一些巧妙的位模式比如0xDEADC0DE,0xDEADBEEF等等。
現在有許多不同的方法來用特定的位模式填充內存。它們主要屬于兩個不同的類別;基于IDE或鏈接器。在IDE實現中,隱藏在屬性菜單深處的是一個“填充內存”的選項。根據IDE和工具鏈的不同,可能會有額外的選項來設置特定的模式,或者工具可以自行決定。當選擇“填充內存”選項時,大多數IDE工具要求開發人員選擇將要填充的內存范圍。這反過來又迫使嵌入式開發人員不斷地監視應用程序在。鏈接器的文本部分。
基于鏈接器的方法為開發人員提供了更加靈活地定制填充解決方案的能力。例如,使用GNU工具鏈,可以創建一個包含FILL()鏈接器命令的新部分輸出。向該命令傳遞應該用于填充存儲器的位模式。從這個內存段中,可以使用原點和長度函數來獲得將要被填充的內存段的大小。允許用位模式自動填充存儲空間,而不需要開發者管理。以下是可以找到一個帶有名為m_text的. text部分的GNU鏈接器的填充部分的例子。
.fillsection :
{
FILL(0xAA55AA55);
. = ORIGIN(m_text) + LENGTH(m_text) – 1;
BYTE(0xAA)
} > m_text
空內存的結果是,在查看編譯期間生成的內存文件時,請求的位模式會填滿內存:
S記錄中的位模式
使用鏈接器文件的一個優點是,項目可以配置為在填充內存和不填充內存的鏈接器之間切換。使用內存填充的缺點之一是每個內存位置都被寫入。這意味著,如果你試圖調試應用程序,每次更改代碼時,你都必須等待所有閃存寫入,即使應用程序不會影響它。這可能會給實施階段增加大量時間。因此,內存填充應該在開始時設置,并作為任何代碼提交的一部分,但仍然提供為調試啟用和禁用它的能力。請記住,開發人員希望盡可能多地使用這種內存填充來捕捉任何意外的行為。
用中斷向量或停止命令正確地實現填充命令可以增加軟件系統的完整性。如果出現錯誤指針、單事件擾亂或其他問題,導致應用程序從意外的存儲位置開始執行代碼,則填充位模式可以將程序執行引導回已知位置,在該位置,嵌入式開發人員進行適當的錯誤處理過程可以恢復系統。每個IDE和MCU實現該功能的方式略有不同,但通常不會比查看如何使用FILL命令的鏈接器數據表復雜多少。