沙德鵬,彭 剛
(交通運輸部 天津水運工程科學研究院,天津 300456)
所謂系統的移植就是通過修改系統內核的原代碼,使其能夠在其它微處理器或控制器上運行。uC/OS-ⅱ是著名的源代碼公開的實時內核,它是一個完整的、可移植、固化、裁剪的搶占式實時多任務內核。S3C2440是三星公司推出的高性能ARM9處理器,片上資源豐富,支持NorFlash和NandFlash兩種啟動方式,具備I-Cach、D-Cach以及MMU微處理器。將uC/OS-ⅱ移植到S3C2440上,能夠有效地管理其硬件資源,縮短程序的開發周期,降低系統維護的難度。uC/OS-ⅱ在S3C2440上的移植主要包括初始化S3C2440、修改uC/OS-ⅱ的底層代碼兩部分。
初始化即編寫啟動代碼,啟動代碼就是處理器在啟動時要執行的一段代碼。其主要任務是初始化處理器模式、設置堆棧、初始化變量等。由于以上操作與處理器體系結構和系統模式密切相關,所以啟動代碼都是由匯編語言編寫,不同的處理器,啟動代碼一般不同。S3C2440的啟動過程如圖1所示。

圖1 S3C2440啟動代碼Fig.1 S3C2440 start code

圖2 中斷響應過程Fig.2 Interrupt the response process
正常的程序因為一些固定的原因而使CPU停止,我們稱之為異常。異常事件由CPU產生,不同的原因產生不同的異常。S3C2440共有7類異常。當異常發生時,系統執行完當前的指令后,將跳轉到相應的異常中斷處理程序處執行,在異常中斷處理程序執行完成后,程序返回到發生中斷指令的下一條指令處執行[1]。
中斷向量表中指定了各異常中斷及其處理程序的對應關系,它通常放在處理器地址的低端,在S3C2440中,異常中斷向量表的大小為32 B,其中每個異常中斷占據4 B的大小,共可容納8個異常中斷,包括一個保留中斷。在S3C2440的啟動代碼中,每個異常中斷對應的中斷向量中存放了一個跳轉指令或者一個向PC寄存器復制的數據訪問指令。通過這條跳轉指令,系統將展開一個宏,引導程序跳轉到其中斷服務程序的入口處執行中斷服務程序 (復位中斷除外)。如果發生的是復位中斷,系統直接跳轉到相應的匯編代碼,其過程如圖2所示。
S3C2440 CPU默認的工作主頻為12 MHz或者16.9344 MHz,這里最常用的是12 MHz。使用PLL電路可以產生更高的主頻,供CPU及外圍電路使用。S3C2440有兩個PLL:MPLL和UPLL,UPLL專用于USB設備。MPLL用于CPU及其外圍設備。MPLL產生三部分時鐘頻率:FCLK、HCLK、PCLK。FCLK用于CPU核,HCLK用于AHB總線,PCLK用于APB總線。S3C2440鎖相環回路電路如圖3所示。

圖3 鎖相環電路Fig.3 Phase-locked loop circuit
欲使S3C2440的鎖相環電路正常工作,產生需要的時鐘信號,必須通過設置CLKDIVN寄存器的值來設置鎖相環P、M、S三個參數的值。同時還要通過設置LOCKTIME寄存的值確定鎖相環的鎖定時間[2]。FCLK的啟動過程:①上電幾毫秒以后晶振開始輸出穩定信號,此時FCLK=晶振頻率,單片機復位信號恢復高電平之后,CPU開始執行指令;②設置完CLKDIVN之后,需要經過一段時間MPLL才能穩定輸出,這段時間由設定的LOCKTIME值來決定,在這段時間之內(Lock Time)FCLK停止震蕩,CPU停止工作;③Lock Time之后,MPLL輸出穩定,FCLK開始震蕩,S3C2440工作在新的FCLK之下,FCLK 的值與 P、M、S的關系如式(1)所示:
FCLK=MPLL=((M+8)Fin)/((P+2)+2S) (1)
系統確定FCLK之后,通過分頻獲得HCLK和PCLK。通過設置PLLCON寄存器中FDIVN、HDIVN和 PDIVN的值可以獲得 FCLK:HCLK:PCLK不同的比例關系。從而獲得不同的HCLK和PCLK。其比例關系如表1所示。

表1 HCLK和PCLK比例關系Tab.1 HCLK and PCLK ratio relationship
S3C2440提供1 G的外存儲空間,共分為8個塊兒(bank),每個塊兒的大小為128 M。8個塊中有6個ROM,2個RAM,前7個塊兒的起始地址固定,最后一個的起始地址可以調整,最后兩個塊兒的大小可編程,支持SDRAM的自刷新和掉電模式。系統上電后,外存儲空間不工作,欲使用外存儲空間必須初始化外存儲空間的控制寄存器。外存儲器的控制寄存器包括 BWSCON、BANKCON[0:7]、MRSRB6、MRSRB7,S3C2440的外存儲空間分布如圖4所示。

圖4 ARM外存儲空間示意Fig.4 ARM external storage space diagram
S3C2440共有7種工作模式,分別是User模式、FIQ 模式、IRQ 模式、Supervisor模式、Abort模式、Undefined模式和System模式。除了User模式和System模式共用同一堆棧外,其它各模式都有自己的堆棧,在進入主函數前需要設置各堆棧的起始地址,設置堆棧的示意性代碼如下:

S3C2440的程序代碼經過編譯和鏈接之后生成的bin文件稱之為鏡像文件,鏡像文件由RO段、RW段和ZI段三部分組成。鏡像文件存儲在ROM中,ROM中存儲鏡像文件的區域稱為加載域,但是加載域只存儲RO段和RW段,不存儲ZI段,因為ZI段的數據全部為0。要得到S3C2440能夠運行的程序必須將鏡像文件的RO段和RW段搬運到連接器制定的區域,同時創建ZI段,這個區域稱為運行域。ARM連接器在創建運行域的同時還創建了5個符號,通過這5個符號可以計算出各個段的起始地址和結束地址。連接器創建的符號為∣Image$$RO$$Base∣、∣Image$$RO$$Limit∣、 ∣Image$$RW$$Base∣、∣Image$$ZI$$Base∣、∣Image$$ZI$$Limit∣,與各個段起始地址與結束地址的對應關系如下[3]:

按照上述對應關系將加載域中的鏡像文件搬運到運行域然后創建ZI段即可得到可以運行的程序。
uC/OS-ⅱ的大多數代碼用C語言編寫,與CPU無關,但是有3個文件與CPU有關針對不同的CPU文件的內容部一樣。這3個文件分別是OS_CPU.H、OS_CPU_A.ASM、OS_CPU_C.C; 要使得 uC/OS-ⅱ能夠在S3C2440上運行,必須完成者3個文件的移植。
AR9體系結構中存在虛擬地址和物理地址,虛擬地址指的是程序要訪問的地址,物理地址指的是程序代碼存放的地址,同一個虛擬地址可以訪問到不同的物理地址,經過代碼搬運與復制之后,單片機的代碼位置發生了變化,但是中斷向量的位置是固定的,一旦有中斷發生,單片機的PC指針仍然指向原來的中斷向量地址,這樣會產生錯誤,導致程序不能正常運行。要避免這種問題,必須進行地址重映射,將存放中斷向量的首地址映射為0。在ARM的內存中存有一張由4096個地址描述符組成的表,每一個地址描述符描述了1 M空間的映射關系,ARM在訪問虛擬地址的時候通過插敘與虛擬地址對應的地址描述符來訪問,結構如圖5所示。

圖5 地址描述Fig.5 Address description
OS_CPU.H包括了用#define語句定義的與處理器相關的常數宏以及類型。OS_CPU.H的移植主要包括三部分內容:與編譯器相關的數據類型、臨界段代碼的保護函數(OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL())、宏定義(OS_TASK_SW())。
不同的處理器有不同的字長,所以uC/OS-ⅱ的移植包括了一系列數據類型的定義,以確保其可移植性,uC/OS-ⅱ不適用 C語言中的 short、int、 以及long等數據類型,因為它們是與編譯器相關的,是不可移植的。uC/OS-ⅱ在OS_CPU.H中定義了可移植的整形數據結構。在移植的過程中用戶需查閱文檔,找出對應于uC/OS-ⅱ的標準的數據類型。
為了避免臨界段代碼免受多任務中斷服務子程序的破壞,uC/OS-ⅱ在進入中斷之前先關中斷,然后進入臨界段代碼,臨界段代碼執行結束之后,uC/OS-ⅱ開中斷,不同的編譯廠商開關中斷的方式不一樣,為了隱藏編譯廠商提供的不同的方法,uC/OS-ⅱ定義了兩個宏:OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()。在移植過程中,需根據編譯器的特點完成這兩個宏的移植[4]。
OS_TASK_SW()是OS_CPU.H中定義的宏,是uC/OS-ⅱ系統中定義的一個重要的宏,主要完成從低優先級到高優先級任務的切換,OS_TASK_SW()主要是在任務級中被調用。必須用匯編語言實現,其流程如圖6所示。

圖6 OS_CPU.H移植流程Fig.6 Flow chart of OS_CPU.H porting
OS_CPU_C.C包含了uC/OS-ⅱ的10個簡單的函數,除OSTaskInit()外,其余 9個只須聲明,但是可以不包含任何代碼。OSTaskInit用于初始化任務的棧結構,uC/OS-ⅱ的每個任務建立后都有一個棧,用于保存任務的現場,棧的結構如圖7所示。

圖7 匯編地址Fig.7 Assembled address
OS_CPU_A.ASM中包含了4個匯編函數:OSSrartHighRdy、OSCtxSw、OSIntCtxSw 以 及 OSTick-ISR(),這4個匯編函數與CPU硬件息息相關,在移植的過程之中必須用匯編語言實現。如果編譯器支持插入匯編代碼就可以將所有與處理器相關的代碼放到OS_CPU_C.C中,而不必再有單獨的匯編語言文件。
OSCtxSw函數即為OSCtxSw(),在OS_CPU_C.C中宏定義 #define OSCtxSw(),OSCtxSw 將 OSCtxSw()定義為宏,通過引用宏直接調用匯編函數OSCtxSw,OSIntCtxSw用于中斷級的任務調度,其作用類似于OSCtxSw,兩者的主要區別在于OSCtxSw用于任務級的任務切換,而OSIntCtxSw用于中斷級的任務切換,OSIntCtxSw的代碼實現比較簡單,OSIntCtxSw在中斷中調用,在中斷之后,中斷服務函數已經保護了被中斷任務的現場,所以OSIntCtxSw函數無需再做保護現場的工作,其它功能與OSCtxSw相同。
OSStartHighRdy函數主要在OSSart中調用,其主要功能是就緒態中的任務中優先級最高的任務開始運行。OSStartHighRdy的示意性代碼如圖8所示。
uC/OS-ⅱ要求用戶提供一個周期性的時鐘源來實現時間的延遲和超時的功能,時鐘的節拍應該每秒發生10~100次,當時鐘節拍中斷發生,系統調用時鐘節拍中斷服務子函數OSTickISR。

圖8 示意性代碼Fig.8 Schematic code
隨著嵌入式應用的快速發展,嵌入式系統的應用領域涉及方方面面,不同的應用也對系統提出了不同的要求,uC/OS-ⅱ作為開源的嵌入式操作系統其代碼短小精悍,提供了操作系統的基本功能,具有可移植、可固化、可裁剪、搶先調度、多任務運行的特定。但是嵌入式系統針對的是不同的微處理器,因此只能提供內核,與處理器相關的底層代碼必須單獨開發。經過上述工作之后uC/OS-ⅱ能夠在S3C2440的單片機上穩定運行,可以在此基礎上進一步完成程序的開發。
參考文獻:
[1] 方華,龔望宜,陳昭飛.一種基于stm32+μCOS-Ⅱ+μCGUI的嵌入式控制系統的構建[J].信息通信,2015(2):65-66.
[2] 劉波文,孫巖.嵌入式實時操作系統ΜC/OS-Ⅱ經典實例:基于STM32處理器[M].北京:北京航空航天大學出版社,2014.
[3] 劉鯉晞,陳揚.基于S3C2410A的μC/OS-Ⅱ和μC/GUI的整合移植[J].中國高新技術企業,2009(4):96-97.
[4] 袁禹,周國榮.μC/OS-Ⅱ和嵌入式圖形界面的整合移植[J].電子技術,2008,45(1):130-133.