嵌入式系統/RTOS 實現
本節中的章節將討論編寫自己的即時作業系統所涉及的一些通用概念。讀者可能能夠閱讀和理解這些頁面中的材料,而無需事先了解作業系統設計和實現,但那些主題的背景知識肯定會有所幫助。
需要記住的一點是,一些嵌入式系統被鎖起來,預計在沒有重新啟動的情況下執行多年。如果我們使用傳統的記憶體管理方案來控制記憶體分配,最終可能會導致記憶體碎片,這會佔用寶貴的時間來整理碎片,並且對於時間敏感的任務來說是一個主要問題。因此,本頁將討論如何在 RTOS 中實現記憶體管理方案,並將討論 malloc( ) 和 free( ) 的基本實現。
有多種方法可以處理記憶體
- 有些系統從不進行 malloc() 或 free() - 所有記憶體都在編譯時分配。
- 有些系統使用 malloc() 和 free() 並進行手動垃圾回收。
- 在手動垃圾回收中,有可能導致記憶體碎片如此嚴重,以至於有一天系統會鎖定,因為沒有一塊足夠大的記憶體來滿足合理大小的 malloc() 請求,儘管許多空閒記憶體塊的總大小遠遠超過了請求的 malloc(),這將是糟糕的。
- 一個微不足道的小錯誤可能會慢慢洩漏記憶體,直到系統耗盡記憶體並鎖定,這將是糟糕的。
- 一些早期的自動垃圾回收方案在垃圾回收和/或記憶體整理期間會進行“停止世界”幾秒鐘。這樣的系統可能會錯過即時截止時間,這將是糟糕的。
- 一些後來的自動垃圾回收方案進行“增量”垃圾回收和記憶體整理。
- 許多即時系統從一組固定大小的記憶體塊池中一次分配一塊記憶體。這完全消除了外部碎片。
嵌入式系統有一個連線到某些硬體(LED、按鈕、限位開關、電機、序列埠、電池充電器等)的微處理器。
每個硬體部分通常都與一小段軟體相關聯,稱為“任務”。例如,“檢查鍵盤並確定自上次檢查以來是否有任何鍵被按下”。或者“檢查主軸的當前位置,並更新 PID”。
任務通常有即時限制,例如
- 在撞擊限位開關後,電機必須在 1/10 秒內關閉,以避免永久性損壞
- PID 迴圈必須至少每 1/100 秒更新一次,以避免振盪
- MP3 播放器必須以 44.1 kHz 的頻率解碼新樣本 - 不快,否則聽起來像松鼠 - 不慢,否則聽起來像在水下。
一些嵌入式系統只有一個任務。
其他嵌入式系統只有一個微控制器連線到許多不同的硬體 - 它們需要“多工處理”。
大多數 RTOS 都提供了一些方法來允許任務相互通訊和同步,通常使用以下一種或多種方法
- 訊息傳遞(通常是最高優先順序訊息優先,而不是先進先出)
- 事件標誌
- 互斥機制:序列化令牌、互斥體、訊號量、監視器等
“任務排程程式”(或通常稱為“排程程式”)是軟體中排程(選擇)下一個要執行的任務的部分。
排程程式可以說是 RTOS 中最難實現的元件。排程程式維護一個表格,記錄系統中每個任務的當前狀態,以及每個任務的當前優先順序。排程程式還需要管理定時器。
一般來說,任務可以處於 3 種狀態
- 活動。在給定處理器上,一次只能有一個活動執行緒。
- 就緒。此任務已準備好執行,但當前未執行。
- 阻塞。此任務當前正在等待鎖或臨界區變為空閒。
有些系統甚至允許其他狀態
- 休眠。任務自願放棄控制一段時間。
- 低優先順序。此任務僅在所有其他任務都處於阻塞或休眠狀態時才執行。
排程程式有兩種呼叫方式
- 當前任務自願 yield() 給排程程式,直接呼叫排程程式,或者
- 當前任務已“執行足夠長的時間”,定時器硬體會中斷它,而定時器中斷例程會呼叫排程程式。
排程程式必須儲存當前任務的當前狀態(將所有暫存器的內容儲存到與該任務關聯的記憶體中),它必須檢視任務列表以查詢就緒狀態中優先順序最高的任務,然後必須將控制權切換回該任務(透過從與新任務關聯的記憶體中恢復所有暫存器值)。
排程程式應首先檢查以確保它已啟用。如果排程程式已停用,則不應該搶佔當前執行緒。這可以透過檢查當前全域性標誌值來實現。有些函式希望停用排程程式,因此此標誌應透過某些訪問器方法可訪問。維護全域性標誌的另一種方法是簡單地說任何希望停用排程程式的函式都可以簡單地停用定時器。這樣排程程式永遠不會被呼叫,也不需要檢查任何標誌。
一些 RTOS 在系統呼叫的整個持續時間內都會停用程序排程程式 - 為了避免錯過截止時間,這需要系統呼叫非常快地完成。其他 RTOS 有可搶佔的系統呼叫;它們只在極短的“臨界區”內停用程序排程程式和其他中斷。
我們將在下一章鎖和臨界區中更多地討論那些需要(短暫地)停用排程程式的函式,以及它們在臨界區內的操作。
另一本書作業系統設計/排程程序/搶佔更詳細地介紹了各種排程程式演算法。
RTOS 和其他作業系統的最大區別之一是 RTOS 試圖最大程度地減少中斷延遲 - 對外部硬體的響應時間。這需要最大程度地減少停用中斷(包括定時器中斷)的時間。一些 RTOS 供應商釋出了最壞情況下的中斷停用時間。
- "即時系統的設計模式:資源模式" 由 Bruce Powel Douglass 2002 年撰寫
- Microchip RTOS 應用筆記 包括“Microchip AN585:面向 PIC16/17 的即時作業系統”,其中描述了編寫自己的 RTOS。
- Greg Hawley 指出,“在大多數情況下,購買 RTOS 是比...從頭開始構建 RTOS 更好的選擇”。
- "完美的即時作業系統" 作者:Colin Walls 2004年 [連結失效]
- "真正簡單的記憶體管理:胖指標" 描述了一種簡單的垃圾回收和記憶體碎片整理方案,該方案與小型即時系統相容(它從不進行“停止世界”操作)。
- "與 8 位 MCU 作業系統調情" 作者:Dave Armour 2009年 描述了實現搶佔式作業系統所需的最基本功能:TaskCreate()、TaskDestroy() 和一個非常簡單的定時器驅動的任務切換器。“FLIRT” 使用了 144 位元組的快閃記憶體。
- "搶佔式示例程式碼" 註釋良好,不到 200 行程式碼的示例演示了兩個任務的搶佔。非常基礎,在任何方向上都有很多改進的空間。