摘? 要: 介紹了一種在嵌入式實時操作系統內核(以下簡稱實時內核)上實現RAM盤的方法,配合接受用戶命令的Shell任務,可實現嵌入式系統的多任務動態加載和監控,擴展了實時內核的應用領域。實時內核采用目前十分流行的免費內核μC/OS-II,硬件平臺為通用現場總線控制器系統。
關鍵詞: μC/OS-II內核? 嵌入式系統? 通用現場總線控制器(GPFC)? ColdFire
?
1 嵌入式RTOS
目前,嵌入式RTOS的應用領域越來越廣泛。已經有80多個RTOS廠商生產面向8位、16位、32位、甚至64位微處理器的RTOS產品。商業的實時操作系統如VxWorks,pSOS,VRTX,WindowsCE等功能完善,提供了完備的開發環境,但大多價格昂貴,不提供源代碼(即所謂的黑箱)。用戶不了解其工作機制,更不能進行修改和擴展。某些商業系統還要求用戶在產品投產后繼續支付軟件費用。這對于國內的用戶開發中小應用系統來說,是一項沉重的負擔。而采用開放源代碼的實時內核不失為一種選擇。開放源代碼的另一個好處是用戶可以根據具體需要刪改和擴展功能。本文將以μC/OS-II在通用網絡控制器上的應用為例,說明開放源代碼的實時內核在可擴展性方面的優點,以及筆者在使用中的一些心得體會。
2 通用現場總線控制器
GPFC(General Purpose Field bus Controller)——通用現場總線控制器是用于加速器數據采集系統中的網絡控制器,由德國國家同步輻射實驗室(DESY)Dr. Clausen Matthias領導的研究小組開發。用于不同種類的現場總線、以太網之間的通訊控制,功能相當于不同類型子網之間的網關(關于GPFC的技術細節,感興趣的讀者可以查詢DESY的主頁http://www.desy.de)。系統微控制器采用Motorola公司68K家族的32位MCU ColdFire 5206E。在33MHz總線頻率下能達到17MIPS的處理能力。由于ColdFire將片選邏輯電路、總線控制器、DRAM控制模塊等全部集成在MCU內部,使得外圍電路變得十分簡單。系統配有32MB DRAM和1MB Flash RAM,并有兩個網絡接口A和B。該系統的硬件設計非常靈活,網絡接口配以不同的驅動電路,可支持以太網、CAN、Profibus、MIL1553等多種現場總線,實現網絡間的連接和控制。只要采用不同的網絡協議,就可以連接不同的子網,實現不同的控制。GPFC配以不同的網絡模塊可以替代目前廣泛使用的VME工控系統,由于舍棄了VME昂貴的機箱、總線板,大幅度減低了主機成本。GPFC系統結構示意如圖1所示。
?
?
3 在GPFC上運行RTOS
GPFC的系統軟件基于嵌入式實時操作系統,國外是在VxWorks上開發的,主要是兩個獨立的任務分別處理兩個網絡接口的通訊協議。為了擴展GPFC的應用范圍,系統軟件包中包含了各種可能用到的網絡協議,都以獨立的任務形式存在。用不上的任務處于休眠狀態,如果需要連接某種類型的網絡,只要運行針對某種網絡協議的任務就行了。
VxWorks價格昂貴,在國內買一套要幾十萬元人民幣。為了滿足國內應用要求,筆者希望尋找一種廉價的實時內核,一方面可降低軟件方面的成本,同時可根據自己的需要定制軟件。經過調研,決定采用當前十分流行的μC/OS-II作為實時內核。
μC/OS-II是基于優先級的搶占式實時多任務內核,其絕大部分代碼是由C寫成的。目前已經應用于包括Motorola 68000系列,以及Intel 80x86等各種處理器上,在世界控制領域取得了一席之地。μC/OS-II的可應用領域非常廣闊,涵蓋了幾乎所有的實時應用。μC/OS-II是完全免費的,全部源代碼都可以從Internet上獲得。
μC/OS-II是面向中小型嵌入式系統的。如果包含全部的功能模塊(信號量、消息郵箱、消息隊列及相關函數),編譯后的μC/OS-II內核大約有6KB;如果只保留最核心的代碼,則可壓縮到3KB,這使得μC/OS-II可以用于更小規模的應用系統。同時,由于系統的可擴展性,稍加修改可以用于更大規模的系統上。RAM的占用與系統中的任務數有關,任務的堆棧要占用大量的RAM空間,堆棧的大小取決于任務的局部變量、緩沖區大小及可能的中斷嵌套的層數。對于一般的中小系統,任務堆棧可以取幾百字節到幾千字節。對于頻繁中斷和高吞吐率的系統,要為任務預留足夠的堆棧空間。本系統中為每個任務分配了512KB的堆棧空間,并有堆棧越界檢查。
采用μC/OS-II所遇到的主要問題是μC/OS-II本身不帶文件系統,缺乏調試工具和手段。為了方便調試和日后的管理操作,基于μC/OS-II的開放源代碼和可擴展性,筆者將Linux的RAM盤、文件系統和用戶 Shell移植到了μC/OS-II上并編寫了內存管理模塊,實現內存的動態分配和釋放。系統中運行的任務可以對RAM盤進行文件操作,文件系統可以為任務保存數據并提供了統一的接口。通過Shell任務,用戶可以登錄到系統中,運行或者掛起任務,以處理不同的通訊協議,實現任務的動態管理。在調試過程中,可以通過命令查看各個任務的運行狀態。而任務以文件的形式保存在RAM盤中,不同種類的任務保存在不同的目錄中,方便了管理和維護。
4 RAM盤的擴展方法
RAM盤采用了和Linux EXT2系統類似的文件系統。EXT2是一種高效、安全的文件系統。圖2是EXT2的邏輯布局。它由一個引導塊和重復的塊組組成,每個塊組又由超級塊、組描述符表、塊位圖、索引節點位圖、索引節點表、數據區組成。文件以樹型目錄形式組成。不同點在于磁盤文件系統的操作單元是磁盤塊,而RAM盤所操作的單元是內存塊。在筆者為GPFC設計的RAM盤中,將內存最高端的4MB劃分為RAM盤空間,每一個邏輯塊為512字節。限于篇幅所限,關于EXT2系統的細節,請感興趣的讀者參考有關Linux文件系統的資料,本文主要介紹如何在RAM盤中實現及主要的數據結構。
?
?
其中引導塊存系統的引導代碼,由于RAM盤不用來引導系統,所以可不必設定引導塊。超級塊用來存放EXT2文件系統整體信息的數據結構,是EXT2的核心所在。超級塊記錄文件系統當前狀態,盤有多大,能存放多少文件,何處可以找到空閑空間和用于文件系統管理的信息。用于管理磁盤的超級塊非常復雜,用于RAM盤則可對其進行簡化,簡化后的ram_super_block結構如下:
struct ram_super_block
{
??? ??? long s_inodes_count;?? ?? /*文件系統中節點總數*/
?????? long s_blocks_count;? ?? ?/*文件系統中的塊總數*/
?????? long s_r_blocks_cout; ?? ?/*為超級用戶保留的塊數*/
?????? long s_free_blocks_count;? ??? /*文件系統中空閑塊總數*/
?????? long s_free_inodes_coutnt; ??? /*文件系統中空閑節點總數*/
?????? long s_first_data_block;?????????/*文件系統中的第一個數據塊*/
?????? long s_log_block_size;????????? /*系統邏輯塊的大小*/
???? ?? short s_inode_size;???????????? /*索引節點結構的大小*/
?????? short s_state;?????????????????? /*文件系統的狀態*/
?????? time_t s_wtime;???????????????? /*超級塊最后一次修改的時間*/
}
在文件系統中每一個文件(包含目錄)占據一個索引節點表項。索引節點是一個記錄文件信息的數據結構dinode。訪問文件,其實就是尋找文件對應的索引節點。索引節點集中保存在索引節點表中,索引節點表的第一項固定為根目錄對應的索引節點。用于管理RAM盤文件的dinode定義如下:
struct dinode{
???? short????? di_mode;???????? /*文件模式:是文件還是目錄,是可讀、可寫還是可執行*/
?????? short????? di_nlink;??????? /*和文件相關的鏈接數*/
?????? short????? di_uid;???????? /*文件所有者的標示*/
?????? short????? di_gid;???????? /*文件所有者的組標示*/
?????? long???? di_size;??????? /*文件大小*/
?????? char???????di_addr[ ];??? /*文件數據所在的邏輯塊編號*/
?????? time_t???? di_atime;??????/*文件最后一次訪問的時間*/
?????? time_t???? di_mtime;??????/*文件最后一次修改的時間*/
?????? time_t???? di_ctime;??????/*文件建立的時間*/
}
塊位圖、索引節點位圖用于查找空閑的RAM盤內存塊和索引節點表項。
與文件訪問過程相關的一個主要函數為i_name(),其輸入參數為希望訪問的文件路徑名,輸出值為文件對應的索引節點號。獲得了文件的索引節點號,就可以在索引節點表中找到該節點,從節點的數據結構中就可以知道文件的種類、存儲位置等信息,進一步就可進行讀寫操作。
RAM盤屬于Linux標準設備中的塊設備。作為標準設備,Linux提供了通用的接口函數。用戶可以直接調用標準接口函數對RAM盤進行操作:
#include
#include
#include
#include
int open(const char pathname,int flag);
?????????????????????????????????? /*打開文件,返回文件描述符*/
int close(int fd);??????????????????????? ? /*關閉文件*/
int read(int fd,void buf,int count); /*從文件中讀出數據到緩沖區,返回讀出的字節數*/
int write(int fd,void buf,int count);?????? /*從緩沖區寫數據到文件,返回寫入字節數*/
5 用戶Shell的擴展與實現
用戶Shell是一個在μC/OS-II下獨立運行的任務。Shell啟動后,完成一些必要的初始化操作,進入掛起狀態,等待用戶登錄和輸入。用戶從終端上輸入命令后將喚醒Shell,在筆者設計的Shell程序中可接受的命令包括:cd(改變RAM盤當前目錄),pwd(顯示RAM盤當前目錄),mkdir、rmdir(在RAM盤創立或刪除目錄),ps(顯示當前系統中的任務狀態),kill(終止一個任務的運行)。處理不同通訊協議的任務分別以可執行文件形式保存在RAM盤上不同的目錄中。如果在Shell中鍵入任務的名稱,Shell會在當前目錄下查找是否有匹配的可執行文件。如果有,則調用μC/OS-II中的系統函數OSTaskCreate創立一個新的任務,否則返回錯誤信息。也可以使用kill命令,調用系統函數OSTaskDel終止一個任務的運行。在程序的調試期間,可以使用ps命令查看任務運行狀態。
由于μC/OS-II中的內存管理功能有限,OSTaskCreate函數不能動態分配堆棧空間,OSTaskDel也不能釋放任務的堆棧空間。為此,筆者重新編寫了內存管理模塊,采用頁方式和首次擬合算法實現內存的動態管理。每一內存頁為2KB,系統的內存資源由一個雙向鏈表進行管理。任務函數可調用OSMemAlloc()和OSMemFree()分配和釋放自己所占的內存空間。OSMemAlloc()在空閑內存鏈表中查詢第一個符合要求的內存塊,并分配給任務。而OSMemFree()則是將釋放后的內存塊重新添加進空閑內存鏈表中。
在開發過程中,筆者感覺到采用開放源代碼的實時內核的最大優點是可擴展性和可裁剪性,可以根據需要定制出最精練的內核結構。μC/OS-II的本意是為中小型嵌入式系統設計的,對于不需要的部分,可以刪改;當內核缺乏某些功能,設計者很容易自行設計和添加,從而可以應用在更大型的系統上。其性能可以同昂貴的商業實時操作系統相媲美,而這種改動和擴展并不難。這正是開放源代碼軟件的生命力所在。
?
參考文獻
1 Jean J. Labrosse.MicroC/OS The Real-Time Kernel.R&D Publications, Inc
2 Jean J. Labrosse.MicroC/OS-II The Real-Time Kernel.R&D Publications, Inc
3 Jean J. Labrosse.邵貝貝譯.嵌入式實時內核.北京:電力出版社