1. 程式人生 > >UCosII移植之OS_CPU.H詳解

UCosII移植之OS_CPU.H詳解

資料型別

 /******************************************************************************

*      定義資料型別    

******************************************************************************/

 typedef unsigned char  BOOLEAN;

typedef unsigned char  INT8U;                 /*Unsigned  8 bit quantity       */

typedef signed   char INT8S;                 /*Signed    8 bit quantity       */

typedef unsigned short INT16U;                 /* Unsigned 16 bitquantity       */

typedef signed   short INT16S;                 /* Signed   16bit quantity       */

typedef unsigned int   INT32U;                 /*Unsigned 32 bit quantity       */

typedef signed   int  INT32S;                /*Signed   32 bit quantity       */

typedef float          FP32;                   /*Single precision floating point*/

typedef double         FP64;                  /*Double precision floating point*/

typedef unsigned int   OS_STK;                /*Each stack entry is 32-bit wide*/

typedef unsigned int   OS_CPU_SR;          /*Define size of CPU status register*/

解析:因為CM3是32位寬的,所有OS_STK被型別重定義成32位的unsigned int,CM3的狀態暫存器(xPSR)也是32位寬的,OS_CPU_SR被型別重定義為unsigned int型別重定義是為了方便移植,不同處理器編譯不一樣,比如ARM7 處理器字長為32位,半字長為16位,位元組為8位,因此在移植時涉及到變數型別時只需要修改型別重定義即可。

臨界區

/*******************************************************************************OS_CRITICAL_METHOD=1直接使用處理器的開關中斷指令來實線巨集

*OS_CRITICAL_METHOD=2 利用堆疊保護和恢復CPU狀態

*OS_CRITICAL_METHOD=3 利用編譯器擴充套件功能獲得的程式狀態字,儲存在區域性變數cpu_sr中

******************************************************************************/

#define OS_CRITICAL_METHOD   3        

/********選擇第三種方法********************/

#if OS_CRITICAL_METHOD == 3

/********進入臨界程式碼區********************/

#define OS_ENTER_CRITICAL()  {cpu_sr =OS_CPU_SR_Save();}

/*********退出臨界程式碼區*****************/

#define OS_EXIT_CRITICAL()  {OS_CPU_SR_Restore(cpu_sr);}

#endif

#if OS_CRITICAL_METHOD == 3                                       

OS_CPU_SR OS_CPU_SR_Save(void);

void OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);

解析:一般喜歡使用第三種方法來實現臨界區。

第一種直接開關中斷的實現臨界區的方法很少採用,因為這種方法可能將原本關閉了的中斷意外的開啟。

(簡單的如51微控制器的開關中斷指令EA=1與EA=0,即實現直接使用處理器的開關中斷,但問題是呼叫了OS_EXIT_CRITICAL後,處理器的中斷一定為開啟,而無論在進入臨界程式碼之前的處理器的中斷是開啟或者關閉。但最理想的狀態應該是,在用了OS_EXIT_CRITICAL後,處理器的中斷開啟與否狀態,應該跟進入臨界程式碼段之前處理器的中斷狀態一致)

第二種方法是最高效的實現方法,但是這種方法調整了堆疊指標,對於需要利用堆疊指標間接定址區域性變數的系統並不適用。(x86通常採用第二種方法,因為它有單獨的暫存器來做區域性變數的定址)

(即在關閉中斷之前,通過堆疊快取CPU的中斷暫存器狀態,即記住進入臨界程式碼之前CPU的中斷開啟與否狀態,然後在推出臨界程式碼的時候,只需將堆疊中的CPU中斷狀態暫存器彈出堆疊,這樣即能實現用了巨集OS_EXIT_CRITICAL後,處理器的中斷開啟與否狀態,跟進入臨界程式碼段之前處理器的中斷狀態一致)

第三種方法最保險,雖然效率比第二種方法略低一點。

(一些處理器可以讀取PSW暫存器的值,將包含中斷開關狀態的PSW暫存器值保持在C語言變數中沒在退出臨界程式碼段時,再將區域性變數中的值回寫到PSW暫存器中。STM32可以通過MRS與MSR指令讀寫特殊暫存器,因此選用了第三種方式)

OS_CPU_SR_Save()和OS_CPU_SR_Restore(cpu_sr)在os_cpu_a.asm中實現

其實也可以通過C程式碼(OS_CPU_C.C)中插入彙編的方式來實現:

1.    __asm OS_CPU_SR OS_CPU_SR_Save(void)  

2.    {  

3.        MRS     R0, PRIMASK ; Set prio int mask to mask all (except faults)  

4.        CPSID   I  

5.        BX      LR  

6.    }  

7.    __asm void OS_CPU_SR_Restore(OS_CPU_SR cpu_sr)  

8.    {  

9.        MSR     PRIMASK, R0  

10.      BX      LR  

11.  }  

三堆疊

#define OS_STK_GROWTH        1    

CM3中,棧是由高地址向低地址生長的,因此OS_STK_GROWTH設為1

任務切換

#define OS_TASK_SW()         OSCtxSw()

任務切換巨集,由彙編實現,在os_cpu_a.asm中

函式原型宣告

未作修改應該是這樣

void       OSCtxSw(void);

void       OSIntCtxSw(void);

void       OSStartHighRdy(void);

void       OS_CPU_PendSVHandler(void);

void       OS_CPU_SysTickHandler(void);         

void       OS_CPU_SysTickInit(INT32U  cnts);

 修改:

A:將OS_CPU_PendSVHandler(void)改為PendSV_Handler(void)

B:註釋掉

OS_CPU_SysTickHandler(void)和OS_CPU_SysTickInit(INT32U  cnts)

詳細分析:

A:修改為PendSV_Handler

UCOSII在stm32中的上下文切換是通過觸發一個PendSV的異常(優先順序較低),然後再異常服務程式裡實現的。os_cpu_a.asm中標號為OS_CPU_PendSVHandler和OS_CPU_PendSVHandler_nosave的內容即是。


但是Micrium官方沒有ST公司官方的啟動程式碼,用的是自己的啟動程式碼,在startup_stm32f10x_cl.s中看到在啟動設定中斷向量表時,PendSV的異常標號為PendSV_Handler,因此兩者有矛盾,可選擇不改變ST官方的檔案,即不改變啟動程式碼,修改ucosII的介面檔案中的程式碼


 修改PendSV

(1)在os_cpu.a.asm中



(2)在os_cpu.h中


(3)在stm32f10x_it.h中


B:註釋掉OS_CPU_SysTickHandler(void)

OS_CPU_SysTickHandler(void)定義在os_cpu_c.c中,是systick的中斷處理函式,而在stm32f10x_it.c中已經有該函式的定義


C:註釋掉OS_CPU_SysTickInit(INT32U  cnts)

OS_CPU_SysTickInit(INT32U  cnts)定義在os_cpu_c.c中,用以初始化systick定時器,此函式我們自己實現,故註釋掉