本帖最后由 liuda 于 2015-1-23 20:53 編輯
還限制字數;只能分割拉。
昨天我簡要的把移植UCOS要增加的幾個文件作了簡要概述,今天開始,一個一個文件的進行分析,首先來說說OS_CPU.H:
#ifdef OS_CPU_GLOBALS //這個宏名在OS_CPU_C.C中已定義,那么本文中的OS_CPU_EXT會被extern代替
#define OS_CPU_EXT
#else
#define OS_CPU_EXT extern
#endif
//定義與編譯器無關的數據類型
typedef unsigned char BOOLEAN; //布爾變量
typedef unsigned char INT8U; // 無符號8位整型變量
typedef signed char INT8S; //有符號8位整型變量
typedef unsigned short INT16U; //無符號16位整型變量
typedef signed short INT16S; //有符號16位整型變量
typedef unsigned int INT32U; //無符號32位整型變量
typedef signed int INT32S; //有符號32位整型變量
typedef float FP32; //單精度浮點數(32位長度)
typedef double FP64; //雙精度浮點數(64位長度)
typedef INT32U OS_STK; //堆棧是32位寬度
注: 這里為什么用typedef,因為如果用#define,那么代碼中的每一個相應的類型都會被替代,很有可能會出現問題,畢竟他只是一個替代的關系,且編 譯時間會增加,而用typedef則不會,它就相當于我們C++里面的引用,一樣的思維,在這里面就是說多了一個名稱。還有要注意的是我們怎么知道 unsigned char 就是無符號8位整型變量,可以ARM公司里面下載ADS_CompilerGuide_D.PDF文件,或者在你所裝的ADS1.2目錄里面有一個文件夾 叫PDF,打開它就可以找到,具體頁在259頁。
//與ARM7體系結構相關的一些定義
#define OS_CRITICAL_METHOD 2 //選擇開、關中斷的方式
__swi(0x00) void OS_TASK_SW(void); //任務級任務切換函數
__swi(0x01) void _OSStartHighRdy(void); //運行優先級最高的任務
__swi(0x02) void OS_ENTER_CRITICAL(void); //關中斷
__swi(0x03) void OS_EXIT_CRITICAL(void); //開中斷
__swi(0x40) void *GetOSFunctionAddr(int Index); //獲取系統服務函數入口[自己還未明白]
__swi(0x41) void *GetUsrFunctionAddr(int Index);//獲取自定義服務函數入口[自己還未明白]
__swi(0x42) void OSISRBegin(void); //中斷開始處理
__swi(0x43) int OSISRNeedSwap(void); //判斷中斷是否需要切換
__swi(0x80) void ChangeToSYSMode(void); //任務切換到系統模式
__swi(0x81) void ChangeToUSRMode(void); //任務切換到用戶模式
__swi(0x82) void TaskIsARM(INT8U prio); //任務代碼是ARM代碼
__swi(0x83) void TaskIsTHUMB(INT8U prio); //任務代碼是THUMB
#define OS_STK_GROWTH 1 //堆棧是從上往下長的
#define USR32Mode 0x10 //用戶模式
#define SYS32Mode 0x1f //系統模式
#define NoInt 0x80
#ifndef USER_USING_MODE
#define USER_USING_MODE USR32Mode //任務缺省模式
#endif
#ifndef OS_SELF_EN
#define OS_SELF_EN 0 //允許返回OS與任務分別編譯、固化
#endif
OS_CPU_EXT INT32U OsEnterSum; //關中斷計數器(開關中斷的信號量)
#define OS_CPU_GLOBALS
#include "config.h"
OS_STK *OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt)
{//這個函數是一個指針函數,里面的形參void (*task)(void *pd)也是一個指針函數,就是一個函數的地址,其中task實際上就是我們的用戶任務函數名;pdata是任務開始執行時,傳遞給任務的參數的指針;ptos是分配給任務的堆棧的棧頂指針。
OS_STK *stk; //OS_STK實際就是unsigned int
opt = opt; // 'opt' 沒有使用。作用是避免編譯器警告
stk = ptos; //獲取堆棧指針
//建立任務環境,ADS1.2使用滿遞減堆棧
//注意下面并沒有對SP進行分配空間,因為這個空間本來就是棧,所以沒必要再對SP進行分配
*stk = (OS_STK) task; /* pc */任務的首地址
*--stk = (OS_STK) task; /* lr */任務的首地址
*--stk = 0; /* r12 */
*--stk = 0; /* r11 */
*--stk = 0; /* r10 */
*--stk = 0; /* r9 */
*--stk = 0; /* r8 */
*--stk = 0; /* r7 */
*--stk = 0; /* r6 */
*--stk = 0; /* r5 */
*--stk = 0; /* r4 */
*--stk = 0; /* r3 */
*--stk = 0; /* r2 */
*--stk = 0; /* r1 */
*--stk = (unsigned int) pdata; /*r0,第一個參數使用R0傳遞 */
*--stk = (USER_USING_MODE|0x00); /* spsr,允許 IRQ, FIQ 中斷 */
*--stk = 0; /* 關中斷計數器OsEnterSum; */
return (stk);
}
#if OS_SELF_EN > 0
extern int const _OSFunctionAddr[];
extern int const _UsrFunctionAddr[];
#endif
//關于SWI的使用,最好看下ADS1.2目錄下PDF文件夾下的ADS_DeveloperGuide_D.PDF文件的5.4我在這里稍微簡述一下,SWI是一個軟中斷,即由軟件實現的中斷,它的中斷號可從LR中獲得,不同指令狀態的取法不一樣,至于哪不一樣,看下面的代碼或PDF文件就可以發現答案;還有它的第一操作數是放在r0中,也就是中斷號是從r0取出,但是中斷號必須從LR中經過變換后再load in r0。。
void SWI_Exception(int SWI_Num, int *Regs)
{
OS_TCB *ptcb;
switch(SWI_Num)
{
//case 0x00: /* 任務切換函數OS_TASK_SW,參考os_cpu_s.s文件
// break;
//case 0x01: /* 啟動任務函數OSStartHighRdy,參考os_cpu_s.s文件 */
// break;
case 0x02: /* 關中斷函數OS_ENTER_CRITICAL(),參考os_cpu.h文件 */
__asm
{
MRS R0, SPSR
ORR R0, R0, #NoInt
MSR SPSR_c, R0
}
OsEnterSum++;
break;
case 0x03: /* 開中斷函數OS_EXIT_CRITICAL(),參考os_cpu.h文件 */
if (--OsEnterSum == 0)
{
__asm
{
MRS R0, SPSR
BIC R0, R0, #NoInt
MSR SPSR_c, R0
}
}
break;
//上面兩個切換狀態的匯編函數是對SPSR進行操作呢?因為使用的是軟中斷,程序狀態寄存器CPRS保存在軟中斷對應的SPRS中,軟中斷退出后會把軟中斷對應的SPSR【即管理模式的SPRS】恢復到原來狀態的CPRS中,所以我們只要對SPSR進行操作就可以了。
|