新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 移植μC/OS-Ⅱ

        移植μC/OS-Ⅱ

        作者: 時間:2016-10-08 來源:網絡 收藏

        圖 8.2 在ISR執行過程中的堆棧內容.

        接著,CPU會調用正確的ISR。μC/OS-Ⅱ要求用戶的ISR在開始時要保存剩下的處理器寄存器[F8.2(2)]。一旦寄存器保存好了,μC/OS-Ⅱ就要求用戶或者調用OSIntEnter(),或者將變量OSIntNesting加1。在這個時候,被中斷任務的堆棧中只包含了被中斷任務的寄存器內容。現在,ISR可以執行中斷服務了。并且如果ISR發消息給任務(通過調用OSMboxPost()或OSQPost()), 恢復任務(通過調用OSTaskResume()), 或者調用OSTimeTick()或OSTimeDlyResume()的話,有可能使更高優先級的任務處于就緒狀態。

        假設有一個更高優先級的任務處于就緒狀態。μC/OS-Ⅱ要求用戶的ISR在完成中斷服務的時候調用OSIntExit()。OSIntExit()會告訴μC/OS-Ⅱ到了返回任務級代碼的時間了。

        調用OSIntExit()會導致調用者的返回地址被保存到被中斷的任務的堆棧中[F8.2(3)]。

        OSIntExit()剛開始時會禁止中斷,因為它需要執行臨界段的代碼。根據OS_ENTER_CRITICAL()的不同執行過程(參看8.03.02),處理器的狀態寄存器會被保存到被中斷的任務的堆棧中[F8.2(4)]。OSIntExit()注意到由于有更高優先級的任務處于就緒狀態,被中斷的任務已經不再是要繼續執行的任務了。在這種情況下,指針OSTCBHighRdy會被指向新任務的OS_TCB,并且OSIntExit()會調用OSIntCtxSw()來執行任務切換。調用OSIntCtxSw()也同樣使返回地址被保存到被中斷的任務的堆棧中[F8.2(5)]。

        在用戶切換任務的時候,用戶只想將某些項([F8.2(1)]和[F8.2(2)])保留在堆棧中,并忽略其它項(F8.2(3),(4)和(5)) 。這是通過調整堆棧指針(加一個數在堆棧指針上)來完成的[F8.2(6)]。加在堆棧指針上的數必須是明確的,而這個數主要依賴于移植的目標處理器(地址空間可能是16,32或64位),所用的編譯器,編譯器選項,內存模式等等。另外,處理器狀態字可能是8,16,32甚至64位寬,并且OSIntExit()可能會分配局部變量。有些處理器允許用戶直接增加常量到堆棧指針中,而有些則不允許。在后一種情況下,可以通過簡單的執行一定數量的pop(出棧)指令來實現相同的功能。一旦堆棧指針完成調整,新的堆棧指針會被保存到被切換出去的任務的OS_TCB中[F8.2(7)]。

        OSIntCtxSw()的原型如程序清單L8.3所示。這些代碼必須寫在匯編語言中,因為用戶不能直接從C語言中訪問CPU寄存器。如果用戶的編譯器支持插入匯編語言代碼的話,用戶就可以將OSIntCtxSw()代碼放到OS_CPU_C.C文件中,而不放到OS_CPU_A.ASM文件中。正如用戶所看到的那樣,除了第一行以外,OSIntCtxSw()的代碼與OSCtxSw()是一樣的。這樣在移植實例中,用戶可以通過“跳轉”到OSCtxSw()中來減少 OSIntCtxSw()代碼量。

        程序清單 L8.3 OSIntCtxSw()的原型

        voidOSIntCtxSw(void)

        {

        調整堆棧指針來去掉在調用:

        OSIntExit(),

        OSIntCtxSw()過程中壓入堆棧的多余內容;

        將當前任務堆棧指針保存到當前任務的OS_TCB中:

        OSTCBCur->OSTCBStkPtr= 堆棧指針;

        調用用戶定義的OSTaskSwHook();

        OSTCBCur=OSTCBHighRdy;

        OSPrioCur=OSPrioHighRdy;

        得到需要恢復的任務的堆棧指針:

        堆棧指針 =OSTCBHighRdy->OSTCBStkPtr;

        將所有處理器寄存器從新任務的堆棧中恢復出來;

        執行中斷返回指令;

        }

        OSIntCtxSw()是μC/OS-Ⅱ(和μC/OS)中唯一的與編譯器相關的函數;在我收到的e-mail中,關于該函數的e-mail明顯多于關于μC/OS其它方面的。如果在多次任務切換后用戶的系統崩潰了,用戶應該懷疑堆棧指針在OSIntCtxSw()中是否被正確地調整了。

        8.04.04OSTickISR()

        μC/OS-Ⅱ要求用戶提供一個時鐘資源來實現時間的延時和期滿功能。時鐘節拍應該每秒鐘發生10-100次。 為了完成該任務, 可以使用硬件時鐘, 也可以從交流電中獲得50/60Hz的時鐘頻率。

        用戶必須在開始多任務調度后(即調用OSStart()后)允許時鐘節拍中斷。換句話說,就是用戶應該在OSStart()運行后,μC/OS-Ⅱ啟動運行的第一個任務中初始化節拍中斷。通常所犯的錯誤是在調用OSInit()和OSStart()之間允許時鐘節拍中斷(如程序清單L8.4所示)。

        程序清單 L8.4 在不正確的位置啟動時鐘節拍中斷

        voidmain(void)

        {

        .

        .

        OSInit();/* 初始化 ? μC/OS-II*/

        .

        .

        /* 應用程序初始化代碼 ...*/

        /*... 調用OSTaskCreate()建立至少一個任務 */

        .

        .

        允許時鐘節拍中斷;/* 千萬不要在這里允許!!! */

        .

        .

        OSStart();/* 開始多任務調度 */

        }

        有可能在μC/OS-Ⅱ開始執行第一個任務前時鐘節拍中斷就發生了。在這種情況下,μC/OS-Ⅱ的運行狀態不確定,用戶的應用程序也可能會崩潰。

        時鐘節拍ISR的原型如程序清單L8.5所示。這些代碼必須寫在匯編語言中,因為用戶不能直接從C語言中訪問CPU寄存器。如果用戶的處理器可以通過單條指令來增加OSIntNesting,那么用戶就沒必要調用 OSIntEnter()了。增加OSIntNesting要比通過函數調用和返回快得多。OSIntEnter()只增加OSIntNesting,并且作為臨界段代碼中受到保護。

        程序清單 L8.5 時鐘節拍ISR的原型

        voidOSTickISR(void)

        {

        保存處理器寄存器;

        調用OSIntEnter()或者直接將 OSIntNesting加1;

        調用OSTimeTick();

        調用OSIntExit();

        恢復處理器寄存器;

        執行中斷返回指令;

        }

        8.05OS_CPU_C.C

        μC/OS-Ⅱ的移植實例要求用戶編寫六個簡單的C函數:

        OSTaskStkInit()

        OSTaskCreateHook()

        OSTaskDelHook()

        OSTaskSwHook()

        OSTaskStatHook()

        OSTimeTickHook()

        唯一必要的函數是OSTaskStkInit(),其它五個函數必須得聲明但沒必要包含代碼。



        關鍵詞:

        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 六安市| 娱乐| 新河县| 景洪市| 丹巴县| 澎湖县| 五峰| 普安县| 安化县| 泽州县| 闻喜县| 巴楚县| 阳信县| 信宜市| 天镇县| 平江县| 晋州市| 洪洞县| 额济纳旗| 濮阳市| 库车县| 本溪| 比如县| 马龙县| 乡宁县| 黑龙江省| 长汀县| 秭归县| 永嘉县| 封丘县| 辽源市| 九台市| 镇雄县| 彭泽县| 茌平县| 汨罗市| 怀来县| 海口市| 乌恰县| 郯城县| 嘉义市|