一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

轉(zhuǎn)載一篇寫得不錯(cuò)的UCOS

 筱肆 2014-03-25
分類: uC/OSii 2011-08-14 18:49 1024人閱讀 評(píng)論(0) 收藏 舉報(bào)
 

今天突然有個(gè)想法,是否在其他結(jié)構(gòu)比較簡單的平臺(tái)上移植比較容易一點(diǎn),正好同學(xué)有一個(gè)凌陽的精簡板,反正今天是星期天,就當(dāng)是休息了。

首先肯定是去熟悉SPCE061A的結(jié)構(gòu)和IDE了。主要是存儲(chǔ)器結(jié)構(gòu)、指令系統(tǒng)和中斷這幾個(gè)部分。本來不是做這個(gè)的,沒有必要深究,總體看看,知道在哪些地方查就行,所以看到很快。于是擺好uCOS系統(tǒng)的資料,按照移植步驟,一個(gè)個(gè)文件、函數(shù)地寫好,其他沒有什么,就是時(shí)間節(jié)拍比較難一點(diǎn),用了不少時(shí)間寫,主要是去熟悉凌陽的中斷系統(tǒng),了解幾個(gè)寄存器的用法。按照標(biāo)準(zhǔn)移植函數(shù)步驟寫下來,代碼也就10來行。

在這里我想說的不是如何移植,而是編譯。凌陽的IDE說實(shí)話肯定是不太完善的。因?yàn)槲彝瑢W(xué)本科的時(shí)候做過,那個(gè)時(shí)候似乎聽他提到過這個(gè)問題。不過我今天算是感受到了。

寫好文件,編譯——我的錯(cuò),有一個(gè)函數(shù)寫錯(cuò)了,編譯沒有通過。然后我改了。編譯,???怎么回事,還是這個(gè)錯(cuò)誤?

大體是這樣的,我寫了一個(gè)OSTaskSw函數(shù)(原本想寫OSCtxSw的),結(jié)果,這個(gè)IDE居然還真的認(rèn)出來一個(gè)OSTaskSw,我當(dāng)時(shí)就暈了,我好像在內(nèi)核里沒有看到過這個(gè)函數(shù)嘛。我趕緊去內(nèi)核查找一下,沒有嘛。我把OSTaskSw函數(shù)改成OSCtxSw(OS_CPU.H里),再編譯,還是有。更暈了~

這個(gè)錯(cuò)誤是這樣報(bào)的:

Error L0080: The external symbol "_memset" has not a public definition.

Error L0080: The external symbol "_OSTaskSw" has not a public definition.

memset嘛好說,這應(yīng)該是我沒有包含某個(gè)庫文件,我只是知道這是個(gè)字符串處理函數(shù),應(yīng)該在string.h里面,但是包含了它,還是有這個(gè)錯(cuò)誤(現(xiàn)在還沒有解決,慚愧~),但是OSTaskSw都沒有了還給我報(bào)什么?

后來我想,這個(gè)IDE是GCC的,是不是因?yàn)樵隽烤幾g,鏈接的時(shí)候用了以前的文件?干脆把所有以前編譯生成的文件刪除了(用clear沒有用),再編譯,嘿嘿,還真的沒有這個(gè)錯(cuò)誤了。I 服了HIM。確實(shí)沒有用過,問題都不好找。

今天比較晚了,明天來解決另一個(gè)問題吧!我懷疑最大的可能是在工程文件的組織上有問題,應(yīng)該好好梳理一下。因?yàn)槲野l(fā)現(xiàn),編譯應(yīng)用程序文件是沒有錯(cuò)的,Build的時(shí)候才出現(xiàn)。

 

心頭憋得慌,一大早就跑到實(shí)驗(yàn)室來調(diào)試。弄了半天,把include文件夾中的memset搜索了一遍,就只有一個(gè)string.h里面有嘛。哪里還有其他的哩?難道我包含的地方不對(duì)?“SPCE061A.h”包含在includes.h中,能夠使用,按說所有.c文件都包含includes.h,放在這里是沒有問題的嘛。不過上天要它說不行,我也沒轍啊~

沒辦法,上網(wǎng)查查吧。

一說是版本問題!我意識(shí)到,好像以前看過一個(gè)版本,在OSTask.c中好像是沒有用到memset函數(shù)。那下載一個(gè)老版本的來實(shí)驗(yàn)一下,總不能讓我去改內(nèi)核吧,改出來更多問題,得不償失。我下的是2.00的。

經(jīng)過一番掙扎一般的調(diào)試(很久都沒有怎么用過凌陽的IDE,很多功能不會(huì)用了,又不知道其Bug,出了問題就只好老老實(shí)實(shí)重新編譯等等,確實(shí)很累),總算調(diào)通了。

經(jīng)過記錄下來——為了系統(tǒng)化,把uCOS標(biāo)準(zhǔn)移植偽碼加上對(duì)比。

 

移植準(zhǔn)備:

ucOS-II的移植主要涉及以下三個(gè)文件:

        OS_CPU.H

        OS_CPU_A.ASM

        OS_CPU_C.C

移植的工作包括以下幾個(gè)內(nèi)容:

1. 在 OS_CPU.H 文件中

    聲明10個(gè)數(shù)據(jù)類型

        BOOLEAN

        INT8U

        INT8S

        INT16U

        INT16S

        INT32U

        INT32S

        FP32

        FP64

        OS_STK

    聲明三個(gè)宏

        OS_ENTER_CRITICAL()

        OS_EXIT_CRITICAL()

        OS_TASK_SW()

    設(shè)置一個(gè)常量的值

        OS_STK_GROWTH

2. 編寫四個(gè)匯編語言函數(shù) (OS_CPU_A.ASM)

        OSStartHighRdy()

        OSCtxSw()

        OSIntCtxSw()

        OSTickISR()

3. 用C語言編寫六個(gè)簡單的函數(shù) (OS_CPU_C.C)

        OSTaskStkInit()

        OSTaskCreateHook()

        OSTaskDelHook()

        OSTaskSwHook()

        OSTaskStatHook()

        OSTimeTickHook()

        ………………

4. 一般認(rèn)為上面幾個(gè)方面就構(gòu)成了整個(gè)移植要做的工作,其實(shí)我認(rèn)為還應(yīng)該包含對(duì)Includes.h和OS_CFG.H的配置,因?yàn)檫@些決定了操作系統(tǒng)的功能和編譯的環(huán)境。

移植工作:

 

1、OS_CPU.H

根據(jù)凌陽的數(shù)據(jù)結(jié)構(gòu)特點(diǎn),定義如下:

typedef unsigned char  BOOLEAN;

typedef unsigned char  INT8U;

typedef signed   char  INT8S;

typedef unsigned int   INT16U;

typedef signed   int   INT16S;

typedef unsigned long  INT32U;

typedef signed   long  INT32S;

typedef float          FP32;

typedef double         FP64;

 

typedef unsigned int   OS_STK;

 

#define  OS_CRITICAL_METHOD    2

 

#if      OS_CRITICAL_METHOD == 2               /*一般都使用第二種方法*/

#define  OS_ENTER_CRITICAL()        __asm__("INT OFF /n/t")              /*關(guān)中斷*/

#define  OS_EXIT_CRITICAL()           __asm__("INT IRQ /n/t" "INT FIQ /n/t")                 /*開中斷*/

#endif

 

#define  OS_STK_GROWTH        1                 /*堆棧增長方式,凌陽是從高向低增長*/

 

#define  OS_TASK_SW()         OSCtxSw()               /*任務(wù)切換函數(shù)*/

 

*這里需要說明的是,很多編譯器由于支持軟中斷,所以,這里通常使用的是軟中斷進(jìn)入管理模式,然后進(jìn)行任務(wù)切換(例如在ARM7中)。但是凌陽沒有軟中斷,只好通過函數(shù)調(diào)用的方式進(jìn)行,而不是讓某個(gè)中斷向量指向OSCtxSw()。

 

到這里,OS_CPU.H的工作大體就是這么多了。

2、OS_CPU_C.C

在這個(gè)文件中,最重要的是OSTaskStkInit()函數(shù)的編寫,其他Hook函數(shù)用來擴(kuò)展內(nèi)核功能而不去修改內(nèi)核結(jié)構(gòu)。

先來看看一般堆棧需要初始化成什么樣子:

l         保存參數(shù)(這個(gè)視情況而定,因?yàn)橛行┨幚砥鞯膮?shù)是通過寄存器傳遞的;如ARM7)

l         保存任務(wù)地址,用于保存當(dāng)前任務(wù)(由于凌陽的段寄存器沒用,為0,保存task+1)

l         處理器狀態(tài)字(凌陽應(yīng)該是SR吧,反正我保存的是SR)

l         中斷返回地址保存(這個(gè)好像不太重要,我看ARM7里面就沒有保存)

l         寄存器組

按照這個(gè)步驟,編寫如下:

這里注意,版本不同,聲明的類型也有不同,在2.52中是OS_STK。

void  *OSTaskStkInit (void (*task)(void *pd), void *pdata, void *ptos, INT16U opt)

{

    OS_STK *stk;

 

    opt    = opt;                      

    stk    = (OS_STK *)ptos;               

    *stk-- = *((INT16U*)pdata);

//         *stk-- = *((INT16U*)task);                    //為0,不需要保存

    *stk-- = *((INT16U*)task + 1);

    *stk-- = (INT16U)0x0000;                         //SR不能亂放東西的,因?yàn)檫@個(gè)是程序執(zhí)行用到的

    *stk-- = (INT16U)0x5555;                         //這些就可以隨便放了為了調(diào)試方便,可以放一些有意義的數(shù)值

    *stk-- = (INT16U)0x4444;

    *stk-- = (INT16U)0x3333;

    *stk-- = (INT16U)0x2222;

    *stk-- = (INT16U)0x1111;

    return ((void*)stk);

}

 

*說明:在標(biāo)準(zhǔn)偽碼里面提到一個(gè)模擬ISR的壓棧,暫時(shí)沒有明白是什么意思。(就是說每次任務(wù)的調(diào)度都是一次中斷)

 

3、OS_CPU_A.ASM

首先聲明需要的外部變量和要輸出的變量:

.external _OSTCBCur

.external _OSTCBHighRdy

.external _OSRunning

.external _OSPrioCur

.external _OSPrioHighRdy

.external _OSIntNesting

 

.external _OSTaskSwHook

.external _OSIntEnter

.external _OSIntExit

.external _OSTimeTick

 

.public _OSStartHighRdy

.public _OSIntCtxSw

.public _OSCtxSw

.public _OSTickISR

大概就這些吧

 

1)函數(shù)_OSStartHighRdy

標(biāo)準(zhǔn)函數(shù)偽碼:

void OSStartHighRdy(void)

{

       調(diào)用用戶定義的OSTaskSwHook();

       OSRunning = TRUE;

       得到將要恢復(fù)運(yùn)行的任務(wù)的堆棧指針:

              Stack Pointer = OSTCBHighRdy——>OSTCBStkPtr;

       從新任務(wù)堆棧中恢復(fù)處理器的所有寄存器;

       執(zhí)行中斷返回指令;

}

 

按這個(gè)標(biāo)準(zhǔn)函數(shù),編寫函數(shù)如下:

_OSStartHighRdy:

         CALL        _OSTaskSwHook

         R1 = 1

         [_OSRunning] = R1;

         R1 = [_OSTCBHighRdy]

         SP = [R1]            //注意是所指向的內(nèi)容,調(diào)這個(gè)錯(cuò)誤用了不少時(shí)間

         POPALL             //此函數(shù)只做了任務(wù)切換工作的一半,并沒有保存當(dāng)前任務(wù)的寄存器

         RETI

 

2)函數(shù)_OSCtxSw

 

標(biāo)準(zhǔn)函數(shù)偽碼:

 

void OSCtxSw(void)

{

       保存處理器寄存器;

       在當(dāng)前任務(wù)的任務(wù)控制塊中保存當(dāng)前任務(wù)的堆棧指針:

              OSTCBCur——>OSTCBStkPtr = Stack Pointer;

       OSTaskSwHook();

       OSTCBCur = OSTCBHighRdy;

       OSPrioCur = OSPrioHighRdy;

       得到將要運(yùn)行的任務(wù)的堆棧指針:

              Stack Pointer = OSTCBHighRdy——>OSTCBStkPtr;

       從新任務(wù)的任務(wù)堆棧中恢復(fù)處理器所有寄存器的值;

       執(zhí)行中斷返回指令;

}

 

按這個(gè)標(biāo)準(zhǔn)函數(shù),編寫函數(shù)如下:

 

_OSCtxSw:

         PUSHALL

         R1 = [_OSTCBCur]

         [R1] = SP

         CALL _OSTaskSwHook

         R1 = [_OSTCBHighRdy]

         [_OSTCBCur] = R1

         R2 = [_OSPrioHighRdy]

         [_OSPrioCur] = R2

         SP = [R1]            //所指向內(nèi)容

         POPALL

         RETI

 

 

3)函數(shù)_OSIntCtxSw

 

標(biāo)準(zhǔn)函數(shù)偽碼:

 

void OSIntCtxSw(void)

{

       OSTaskSwHook();

       OSTCBCur = OSTCBHighRdy;

       OSPrioCur = OSPrioHighRdy;

       得到將要運(yùn)行的任務(wù)的堆棧指針:

              Stack Pointer = OSTCBHighRdy——>OSTCBStkPtr;

       從新任務(wù)的任務(wù)堆棧中恢復(fù)處理器所有寄存器的值;

       執(zhí)行中斷返回指令;

}

 

按這個(gè)標(biāo)準(zhǔn)函數(shù),編寫函數(shù)如下:

 

_OSIntCtxSw:

           R1 = [_OSTCBCur]              //在這之前要不要調(diào)整指針,還說不好,因?yàn)椴徽{(diào)整暫時(shí)也可以運(yùn)行

           [R1] = SP            //注意要保存當(dāng)前任務(wù)的堆棧,否則不能返回——

                                       //當(dāng)然最好是放在OSTickISR中,這樣可以避免在后面調(diào)整堆棧指針——

           CALL _OSTaskSwHook

         R1 = [_OSTCBHighRdy]

         [_OSTCBCur] = R1

         R2 = [_OSPrioHighRdy]

         [_OSPrioCur] = R2

         SP = [R1]            //所指向內(nèi)容

         POPALL

         RETI

 

看起來,這個(gè)函數(shù)同OSCtxSw沒有太多的不同,區(qū)別在于如果ISR保存了CPU寄存器,這里不用再保存了。

 

4)函數(shù)_OSTickISR

標(biāo)準(zhǔn)函數(shù)偽碼:

void OSTickISR(void)

{

       保存處理器寄存器;

       調(diào)用OSIntEnter()或者直接給OSIntNesting加1;

       if(OSIntNesting == 1)

       {

              OSTCBCur——>OSTCBStkPtr = Stack Pointer;          //在2.51之前是沒有的

       }

       給產(chǎn)生中斷的設(shè)備清中斷;

       重新使能允許中斷(可選);

       OSTimeTick();

       OSIntExit();

       恢復(fù)處理器寄存器;

       執(zhí)行中斷返回指令;

}

 

按這個(gè)標(biāo)準(zhǔn)函數(shù),編寫函數(shù)如下:

需要注意到是,要在OS_CFG.H中設(shè)置節(jié)拍數(shù)

 
text             //中斷應(yīng)該映射到0地址

.public _IRQ6

_IRQ6:

_OSTickISR:

         PUSHALL

         R1=C_IRQ6_TMB2                      //判斷是否為IRQ_TMB2中斷

         TEST R1,[P_INT_Ctrl]

         JNZ IRQ_TMB2                          //是,進(jìn)入IRQ_TMB2;否,進(jìn)入IRQ_TMB1

IRQ_TMB1:

         R1=C_IRQ6_TMB1                      //清中斷標(biāo)志

         [P_INT_Clear]=R1

          R1=0x0001

           [P_Watchdog_Clear]=R1       //清看門狗

         R1=[_OSIntNesting]          //  中斷嵌套標(biāo)志加1

         R1+=1                                             //  也可call _OSIntEnter

         [_OSIntNesting]=R1             //

                                                        //最好在這里加入保存步驟,省去調(diào)整SP;

                                                         //當(dāng)然如果這里加了,前面就不要再保存了

         call _OSTimeTick

         call _OSIntExit

         POPALL

         reti

IRQ_TMB2:                                             //中斷子程序IRQ_TMB2

         R1=C_IRQ6_TMB2                      //清中斷標(biāo)志

         [P_INT_Clear]=R1

         POPALL

         reti

 

*說明:由于凌陽提供兩個(gè)時(shí)基中斷,需要判斷中斷控制器的值。具體參照手冊(cè)。

到這里,主要的移植工作就完成了。

 

后記:

整個(gè)過程受制于對(duì)凌陽的不熟悉,所以中間編譯的過程比較頭疼,這也反映了移植工作是建立在對(duì)目標(biāo)系統(tǒng)熟悉的基礎(chǔ)之上。

有幾個(gè)問題需要注意:

移植版本:

移植版本不同,內(nèi)核所需要的庫函數(shù)也不同;這個(gè)移植過程遇到了一個(gè)string.h的問題,加上都沒有用,我郁悶。

OSIntCtxSw():

這是我后來在網(wǎng)上看到的,好幾個(gè)實(shí)例中都調(diào)整了SP的值,目的是舍棄多余的數(shù)據(jù)。而在我的移植中,沒有進(jìn)行這個(gè)調(diào)整,也能夠運(yùn)行??赡軈^(qū)別在于對(duì)內(nèi)存的合理使用上。

翻看uCOS_II第二版的304-307頁,我們可以找到答案:

在以前版本中,沒有在OSTickISR()中進(jìn)行中斷時(shí)的堆棧保存:

       if(OSIntNesting == 1)

       {

              OSTCBCur——>OSTCBStkPtr = Stack Pointer;          //在2.51之前是沒有的

       }

因此,在調(diào)用OSIntCtxSw()的時(shí)候,需要先做這個(gè)工作:調(diào)整堆棧指針,標(biāo)準(zhǔn)代碼中給出的是:

       OSIntExit();

       OSIntCtxSw();

不是太明白,這個(gè)調(diào)用不成了自己調(diào)用遞歸了么?實(shí)驗(yàn)過,不行的。

       然后保存當(dāng)前任務(wù)的堆棧指針到當(dāng)前任務(wù)控制塊中。

              OSTCBCur——>OSTCBStkPtr =  Stack Pointer

為了避免調(diào)整指針,最好在OSTickISR中保存堆棧先——

 

在凌陽中,具體操作上將SP的值加7,就是拋棄這7個(gè)數(shù)據(jù)的值。為什么要說7,據(jù)說同編譯器有關(guān),這里也沒有時(shí)間去詳細(xì)追究,網(wǎng)上也沒有相關(guān)的說明,只有自己調(diào)試的時(shí)候打開調(diào)試窗口觀察吧。

我調(diào)試了一會(huì)兒。在任務(wù)切換處設(shè)置一個(gè)斷點(diǎn)觀測。當(dāng)執(zhí)行到POPALL時(shí),SP跳到00d0處(這個(gè)地址值為空),將之前壓棧的值彈出到寄存器中。從下面可以看到,彈棧前,SP指向的是00d0——棧頂;彈棧后,堆棧中的值(包括PC)彈出到寄存器中,SP指向的是00d7,所以這個(gè)值顯然是7了。這也比較符合凌陽的寄存器結(jié)構(gòu)。

   


其實(shí)最好的方法是在OSTickISR中加入中斷嵌套堆棧保存的步驟,這樣就不需要去根據(jù)編譯器調(diào)整堆棧指針了,移植性更強(qiáng)。參考uCOS_II P305、P307。

就在函數(shù)中添加這樣的代碼:

         CMP R1,1          //R1中保存了OSIntNesting的值

         JNZ NOT_SAVE_SP           

SAVE_SP:

         R1 = [_OSTCBCur]

         [R1] = SP

NOT_SAVE_SP:

更多 0
相關(guān)主題推薦
ucos-ii 移植 應(yīng)用程序 匯編語言 數(shù)據(jù)結(jié)構(gòu)
相關(guān)博文推薦
數(shù)據(jù)結(jié)構(gòu)基礎(chǔ)之樹、二叉樹
設(shè)計(jì)師的概念應(yīng)用,讓你更想買 Moto ...
【愛上cocos2d-x之十二】數(shù)據(jù)結(jié)構(gòu)...
Pick-up sticks
并查集的作用
蘋果官網(wǎng)數(shù)據(jù):iOS 7 系統(tǒng)使用率已超...
楊輝三角的隊(duì)列實(shí)現(xiàn)
二叉樹前序、中序、后序遍歷相互求法

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    日韩黄色一级片免费收看| 国产成人午夜av一区二区| 亚洲婷婷开心色四房播播| 欧美成人久久久免费播放| 日本一区二区三区黄色| 成人免费观看视频免费| 少妇一区二区三区精品| 亚洲视频一区自拍偷拍另类| 国产av精品一区二区| 尹人大香蕉一级片免费看| 亚洲免费黄色高清在线观看| 欧美老太太性生活大片| 国产户外勾引精品露出一区| 亚洲一区二区亚洲日本| 91熟女大屁股偷偷对白| 久久精品国产亚洲熟女| 初尝人妻少妇中文字幕在线| 成人午夜激情免费在线| 亚洲欧美日本国产不卡| 欧美成人欧美一级乱黄| 色综合视频一区二区观看| 午夜色午夜视频之日本| 久久精品a毛片看国产成人| 精品人妻一区二区四区| 欧美一区二区日韩一区二区| 91久久精品国产一区蜜臀| 中文字幕久久精品亚洲乱码| 国产日韩中文视频一区| 在线免费观看黄色美女| 中文字幕亚洲人妻在线视频| 好吊妞视频这里有精品| 亚洲一区二区欧美激情| 成人综合网视频在线观看| 精品久久av一二三区| 亚洲一区二区精品免费| 国产高清视频一区不卡| 欧美成人免费夜夜黄啪啪| 一区二区三区四区亚洲专区 | 高清一区二区三区不卡免费| 欧美日韩中国性生活视频| 国产精品白丝久久av|