S3C2416裸機(jī)開發(fā)系列十五_GCC下uCOS的移植(1)
掃描二維碼
隨時(shí)隨地手機(jī)看文章
操作系統(tǒng)是用來管理系統(tǒng)硬件、軟件及數(shù)據(jù)資源,控制程序運(yùn)行,并為其它應(yīng)用軟件提供支持的一種系統(tǒng)軟件。根據(jù)不同的種類,又可分為實(shí)時(shí)操作系統(tǒng)、桌面操作系統(tǒng)、服務(wù)器操作系統(tǒng)等。對(duì)于一些小型的應(yīng)用,對(duì)系統(tǒng)實(shí)時(shí)性要求高,硬件資源有限等的情況下,應(yīng)盡量避免使用復(fù)雜龐大的操作系統(tǒng)(如Linux),使用小型的實(shí)時(shí)操作系統(tǒng)(如uCOS)更能滿足應(yīng)用的需求。筆者此處就uCOS-II的移植作一個(gè)簡(jiǎn)單的介紹。
1. 代碼準(zhǔn)備uCOS-II V2.91源碼,這個(gè)版本的源碼是uCOS-II的最新版本,請(qǐng)讀者自行從Micrium官網(wǎng)或其它網(wǎng)站下載這個(gè)版本的源碼,當(dāng)然,其它版本的uCOS-II也是一樣方式移植的。Micrium官網(wǎng)也給出了一些cpu的移植范例,可供參考,此處是下載源碼,一步一步進(jìn)行移植。
s3c2416啟動(dòng)代碼工程,啟動(dòng)代碼是s3c2416/50/51這系列arm9芯片在運(yùn)行用戶c代碼main函數(shù)之前必須先運(yùn)行的代碼,啟動(dòng)代碼支持sd、Nand啟動(dòng),為用戶設(shè)置系統(tǒng)時(shí)鐘,初始化內(nèi)存,自動(dòng)識(shí)別啟動(dòng)設(shè)備并搬移代碼到RAM,MMU映射,中斷管理等,用戶只需專注于用c開發(fā)其它功能函數(shù)即可。關(guān)于啟動(dòng)代碼以及啟動(dòng)代碼的實(shí)現(xiàn)過程,筆者前面章節(jié)有非常詳細(xì)的介紹。此處以GCC下移植uCOS為講解,下載”GCC啟動(dòng)代碼工程應(yīng)用實(shí)例”中的啟動(dòng)代碼源碼即可。如果在MDK下開發(fā),下載”MDK啟動(dòng)代碼工程應(yīng)用實(shí)例”中的啟動(dòng)代碼源碼。
用戶代碼,用c開發(fā)的所有功能代碼,其中,用戶代碼入口為main()函數(shù),在這里實(shí)現(xiàn)uCOS多任何運(yùn)行代碼。
2. 工程搭建在linux操作系統(tǒng)下任一路徑下新建一個(gè)uCOS的工程目錄,該目錄下新建uCOS-II目錄用來保存uCOS相關(guān)部分。下載uCOS-II V2.91源碼并解壓,把Source目錄全部拷貝到uCOS-II目錄下,同時(shí)在目錄下新建一個(gè)Cfg目錄用來保存uCOS的配置文件,新建一個(gè)Ports目錄用來保存uCOS移植接口文件。
把啟用代碼目錄start_code拷貝到UCGUI目錄下,這部分代碼無需任何的修改。并保留其中的Makefile這些文件。GCC啟動(dòng)代碼下的工程管理Makefile提取自u(píng)boot,可以方便地增加源代碼以及代碼目錄。
在UCGUI目錄下新建apps目錄,用來保存應(yīng)用相關(guān)的源碼。
最終的UCGUI目錄內(nèi)容如下:
uCOS/start_code,保存s3c2416啟動(dòng)代碼相關(guān)的部分
uCOS/app,保存工個(gè)工程的應(yīng)用部分
uCOS/uCOS-II/Cfg,保存uCOS的配置部分
uCOS/uCOS-II/Ports,保存uCOS移植部分
uCOS/uCOS-II/Source,保存uCOS的源碼,通??芍苯犹鎿Q更高版本的源碼
3. uCOS移植uCOS-II應(yīng)用在不同的cpu,需要在uCOS-II/Ports目錄中實(shí)現(xiàn)os_cpu.h、os_cpu_a.s、os_cpu_c.c這三個(gè)文件的修改編寫。
3.1. os_cpu.h的編寫3.1.1. 外部聲明uCOS-II用OS_CPU_GLOBALS和OS_CPU_EXT來聲明外部的變量、符號(hào),這部分如下:
#ifdef OS_CPU_GLOBALS
#define OS_CPU_EXT
#else
#define OS_CPU_EXT extern
#endif
3.1.2. 數(shù)據(jù)類型定義為了確保uC/OS-II的可移植性,在os_cpu.h中聲明了一系列的類型定義。這些類型不依賴于c數(shù)據(jù)類型如int、short、long等。數(shù)據(jù)類型定義如下:
typedef unsigned char BOOLEAN; /* 布爾變量*/
typedef unsigned charINT8U; /* 無符號(hào)8位整型變量*/
typedef signed char INT8S; /* 有符號(hào)8位整型變量*/
typedef unsigned shortINT16U; /* 無符號(hào)16位整型變量*/
typedef signed shortINT16S; /* 有符號(hào)16位整型變量*/
typedef unsigned int INT32U; /* 無符號(hào)32位整型變量*/
typedef signed int INT32S; /* 有符號(hào)32位整型變量*/
typedef float FP32; /* 單精度浮點(diǎn)數(shù)(32位長(zhǎng)度)*/
typedef double FP64; /* 雙精度浮點(diǎn)數(shù)(64位長(zhǎng)度)*/
3.1.3. 棧配置uCOS-II適用于8位、16位、32位的cpu,不同字長(zhǎng)的cpu,其棧字長(zhǎng)也是不一樣的,uCOS-II用OS_STK表?xiàng)n愋?,同時(shí)棧的生長(zhǎng)方式可以由高地址到低地址,也可由低地址到高地址。對(duì)于arm架構(gòu)cpu,棧可以向下,也可以向上增長(zhǎng)。但對(duì)于各個(gè)編譯器是約定棧由高地址向低地址增長(zhǎng)的,棧字長(zhǎng)為32位。棧配置內(nèi)容如下:
typedef INT32U OS_STK; /* 棧是32位寬度*/
#define OS_STK_GROWTH 1 /* 棧是從高往下生長(zhǎng)*/
3.1.4. 臨界區(qū)訪問對(duì)于可搶占式操作系統(tǒng),有一小段關(guān)鍵代碼必須獨(dú)占訪問,如果有一個(gè)任務(wù)(線程)正在訪問臨界代碼,則其它任務(wù)(線程)不能再進(jìn)入該段代碼,直到占有訪問權(quán)的任務(wù)(線程)退出這個(gè)臨界區(qū)。uCOS-II在訪問內(nèi)核臨界區(qū)時(shí)是通過OS_ENTER_CRITICAL()/OS_EXIT_CRITICAL()這兩個(gè)宏開關(guān)中斷來禁止任務(wù)搶占來確保臨界區(qū)不被破壞。通常,臨界區(qū)訪問有三種方式,一是直接開關(guān)中斷,二是從棧中保存/恢復(fù)中斷狀態(tài)再開關(guān)中斷,三是從局部變量保存/恢復(fù)中斷狀態(tài)再開關(guān)中斷。uCOS-II采用了第三種開關(guān)中斷方式,需實(shí)現(xiàn)狀態(tài)保存恢復(fù)開關(guān)中斷CPU_SR_Save()/CPU_SR_Restore(),需引入一個(gè)OS_CPU_SR類型的變量保存cpu中斷狀態(tài),臨界區(qū)中斷訪問內(nèi)容如下:
#define OS_CRITICAL_METHOD 3 /*局部變量保存/恢復(fù)狀態(tài)再開關(guān)中斷 */
typedef INT32U OS_CPU_SR; /*開關(guān)中斷前用來保存/恢復(fù)中斷狀態(tài)*/
#define OS_ENTER_CRITICAL() {cpu_sr =CPU_SR_Save ();} /* 關(guān)中斷 */
#define OS_EXIT_CRITICAL() {CPU_SR_Restore (cpu_sr);} /* 開中斷*/
3.1.5. 函數(shù)聲明uCOS-II需匯編實(shí)現(xiàn)開關(guān)中斷、任務(wù)切換這些與體系結(jié)構(gòu)相關(guān)的功能,在匯編文件os_cpu_a.s中進(jìn)行實(shí)現(xiàn),頭文件進(jìn)行函數(shù)聲明,聲明有如下幾個(gè)函數(shù):
#define OS_TASK_SW() OSCtxSw() /* 任務(wù)級(jí)任務(wù)切換函數(shù)*/
OS_CPU_SR CPU_SR_Save(void);
void CPU_SR_Restore(OS_CPU_SR cpu_sr);
void OSStartHighRdy(void);
void OSCtxSw(void);
void OSIntCtxSw(void);
3.2. os_cpu_a.s的編寫高級(jí)語言不能實(shí)現(xiàn)保存/恢復(fù)寄存器,因此uCOS-II需要編寫匯編實(shí)現(xiàn)六個(gè)簡(jiǎn)單的函數(shù),CPU_SR_Save ()、CPU_SR_Restore()、OSStartHighRdy()、OSCtxSw()、OSIntCtxSw()、IRQ_SaveContext()。
3.2.1. CPU_SR_Save()函數(shù)由于采用從局部變量保存/恢復(fù)中斷狀態(tài)再開關(guān)中斷的方式,用R0返回中斷狀態(tài),并關(guān)閉中斷,該函數(shù)是OS_ENTER_CRITICAL()的宏實(shí)現(xiàn)。
.globl CPU_SR_Save
CPU_SR_Save:
MRS R0, CPSR
ORR R1, R0, #0xC0 // 設(shè)置IRQ,FIQ均禁止中斷
MSR CPSR_c, R1
BX LR // 禁止中斷,返回中斷狀態(tài)到R0中
3.2.2. CPU_SR_Restore()函數(shù)臨界區(qū)訪問完后,需恢復(fù)關(guān)中斷前的中斷狀態(tài),該函數(shù)是OS_EXIT_CRITICAL()的宏實(shí)現(xiàn)。
.globl CPU_SR_Restore
CPU_SR_Restore:
MSR CPSR_c, R0
BX LR
3.2.3. OSStartHighRdy()函數(shù)當(dāng)用戶通過OSStart()啟動(dòng)uCOS內(nèi)核進(jìn)行管理時(shí),OSStart()會(huì)首先調(diào)用OSStartHighRdy()來運(yùn)行已創(chuàng)建任務(wù)中優(yōu)先級(jí)最高的任務(wù),OSStartHighRdy()需完成以下工作:
(1) 禁止中斷切換到管理模式,所有任務(wù)均工作在管理模式
(2) 調(diào)用任務(wù)切換鉤子函數(shù),即先調(diào)用OSTaskSwHook()函數(shù)
(3) 標(biāo)記uCOS-II內(nèi)核已啟動(dòng)運(yùn)行,OSRunning = 1
(4) 獲得最高優(yōu)先級(jí)任務(wù)TCB,得到任務(wù)棧指針,SP切換到任務(wù)棧
(5) 出棧SP中的任務(wù)棧,包括任務(wù)狀態(tài)寄存器CPSR,R0-R12,LR,繼續(xù)執(zhí)行任務(wù)。
#define I_Bit 0x80// IRQ中斷禁止位
#define F_Bit 0x40// FIQ中斷禁止位
#define Mode_SVC 0x13 // 管理模式
#define Mode_SYS 0x1f // 系統(tǒng)模式
.extern OSTaskSwHook
.extern OSRunning
.extern OSTCBHighRdy
.globl OSStartHighRdy
OSStartHighRdy:
MSR CPSR_c, #(I_Bit+F_Bit+Mode_SVC) // 禁止中斷切換到管理模式
LDR R0, =OSTaskSwHook // 調(diào)用任務(wù)切換鉤子函數(shù)
MOV LR, PC // 準(zhǔn)備函數(shù)返回地址