<p id="nxp5x"><big id="nxp5x"><noframes id="nxp5x">

    <var id="nxp5x"><video id="nxp5x"></video></var>

          <em id="nxp5x"></em>

              首 頁 本刊概況 出 版 人 發行統計 在線訂閱 歡迎投稿 市場分析 1 組織交流 1 關于我們
             
            1
               通信短波
            1
               新品之窗
            1
               優秀論文
            1
               通信趨勢
            1
               特別企劃
            1
               運營商動態
            1
               技術前沿
            1
               市場聚焦
            1
               通信視點
            1
               信息化論壇
            1
            當前位置:首頁 > 優秀論文
            嵌入式實時操作系統FreeRTOS在ARM7上移植的實現
            作者:黃鵬程 福州大學 數學與計算機科學學院 福州 351002
            來源:不詳
            更新時間:2009/9/19 19:29:00
            正文:

            1 引言
            FreeRTOS操作系統是一個源碼公開的免費的嵌入式實時操作系統,具有可移植、可裁減、調度策略靈活的特點,可以方便地移植到各種體系結構的微處理器上運行,其最新版本為5.2.0版。
            作為一個輕量級的操作系統,FreeRTOS提供的功能包括:任務管理、時間管理、信號量、消息隊列、內存管理、記錄功能等,可基本滿足較小系統的需要。FreeRTOS內核支持優先級調度算法,每個任務可根據重要程度的不同被賦予一定的優先級,CPU總是讓處于就緒態的、優先級最高的任務先運行。FreeRTOS內核同時支持輪換調度算法,系統允許不同的任務使用相同的優先級,在沒有更高優先級任務就緒的情況下,同一優先級的任務共享CPU的使用時間。在任務的組織實現方面,FreeRTOS內核支持傳統的實現:各任務擁有各自的堆棧,支持完全的搶占式調度。FreeRTOS內核同時支持各任務共享同一個堆棧,使RAM的需求進一步減小。但正因如此,該方式的使用受到相對嚴格的限制。
            本文移植的硬件平臺是由恩智浦公司生產的基于ARM7TDMI核的微處理器LPC2292。開發調試平臺是ARM ADS 1.2。

            2 啟動代碼的編寫
            啟動代碼是芯片復位后進入C語言的main()函數前執行的一段代碼,主要是為運行C語言程序提供基本的運行環境,如初始化存儲系統等。為了能夠進行系統初始化,采用一個匯編文件作為啟動代碼是常見的做法。初始化代碼所完成的操作與具體的硬件平臺相關,但一般包括如下內容:(1)初始化異常向量表;(2)初始化存儲器系統;(3)初始化堆棧;(4)初始化有特殊要求的端口、設備;(5)初始化應用程序的運行環境;(6)改變處理器的運行模式;(7)調用主應用程序。
            需要注意的是,在對處理器每個模式的堆棧指針寄存器進行初始化的時候,用戶模式下的堆棧寄存器必須最后進行初始化。因為在用戶模式下,不能用MSR指令從用戶模式切換到其它的特權模式,所以如果在其它特權模式的堆棧指針被初始化之前切換到用戶模式,就無法對特權模式下的堆棧指針進行初始化。
            第二個需要注意的是,程序使用編譯器分配的空間作為堆棧,而不是按照通常的做法把堆棧分配到RAM的頂端。這樣做有兩個好處:(1)不必知道RAM頂端的位置,移植更加方便。(2)編譯器給出的占用RAM空間的大小就是實際占用的大小,便于控制RAM的分配。

            3 FreeRTOS的移植
            本次一直主要集中在3個文件里面:portmacro.h,port.c,port.s。其中portmacro.h主要包含于編譯器相關的數據類型的定義、堆棧類型的定義以及幾個宏定義和函數說明。而port.c中則包含與移植有關的C函數,包括堆棧的初始化函數、任務調度器啟動函數、臨界區的進入與退出、時鐘中斷服務程序等。port.s中則包含與移植有關的匯編語言函數,包括上下文切換、開/關中斷、任務切換等。移植中關鍵的功能模塊實現如下文所述。
            3.1開/關中斷的實現
            FreeRTOS使用函數portDISABLE_INTERRUPTS() 和portENABLE_INTERRUPTS( )分別實現關中斷和開中斷。這些代碼與處理器有關,需要進行移植。在ARM處理器核中,關中斷和開中斷是通過改變程序狀態寄存器CPSR中的相應控制位來實現的。開中斷的匯編語言函數portENABLE_INTERRUPTS()的代碼如下:
            portENABLE_INTERRUPTS
            STMDB SP!, {R0} ;/* 把R0壓入棧 */
            MRS R0, CPSR ;/* 讀取狀態寄存器到R0 */
            BIC R0, R0, #0xC0 ; /* 允許IRQ、FIQ中斷 */
            MSR CPSR_cxsf, R0 ; /* 回寫R0的值到狀態寄存器 */
            LDMIA SP!, {R0} ;/* R0出棧 */
            BX LR ;/* 函數返回 */
            用類似的方法可以實現關中斷函數portDISABLE_INTERRUPTS()。
            3.2 臨界區的進入與退出
            代碼的臨界段也稱為臨界區,指處理時不可分割的代碼。一旦這部分代碼開始執行,則不允許任何中斷打斷。開中斷和關中斷可以保護臨界代碼段,保證FreeRTOS的臨界代碼不會被多個任務和中斷服務程序同時訪問,避免造成共享數據的不一致性。為了保護臨界區的資源,在進入臨界區之前須關中斷,而臨界區代碼執行完畢后,要立即開中斷。臨界區的退出函數vPortExitCritical()代碼如下:
            void vPortExitCritical( void )
            {
            if( ulCriticalNesting > portNO_CRITICAL_NESTING )
            {
            ulCriticalNesting--; /* 中斷嵌套計數器ulCriticalNesting自減一*/

            /* 如果中斷嵌套層數為零的話,則需要開中斷. */
            if( ulCriticalNesting == portNO_CRITICAL_NESTING )
            {
            /* 調用函數portENABLE_INTERRUPTS()來開中斷. */
            portENABLE_INTERRUPTS();
            }
            }
            }
            用類似的方法可以實現臨界區的進入函數vPortEnterCritical( )。
            3.3 堆棧的初始化

            任務創建函數xTaskCreate()通過調用堆棧的初始化函數pxPortInitialiseStack()來初始化任務的棧結構;實際是定義了任務堆棧上下文(context)的內容。所有的寄存器都保存到堆棧中,堆?雌饋砭拖裰袛鄤偘l生過一樣。上下文的保存格式如圖1所示。
            在堆棧的上下文中,PC存放任務執行的第一條指令,LR保存的是任務的返回地址,SP保存的是任務的堆棧地址。R0存放的是傳遞給任務的參數。CPSR存放的是任務運行時處理器的初始狀態。CriticalNesting存放的是中斷嵌套計數器ulCriticalNesting的值。任務堆棧的上下文保存結構與任務切換的實現緊密相關,所以我們在設計上下文保存結構的時候,要重點考慮實現任務切換的便捷性。
            PC
            LR
            SP
            R12
            .........
            R1
            R0
            CPSR
            CriticalNesting
            圖1 上下文的保存結構


            portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack,
            pdTASK_CODE pxCode, void *pvParameters )
            {
            portSTACK_TYPE *pxOriginalTOS;

            pxOriginalTOS = pxTopOfStack;
            *pxTopOfStack = ( portSTACK_TYPE ) pxCode + portINSTRUCTION_SIZE; /* PC */
            *(--pxTopOfStack) = ( portSTACK_TYPE ) 0xaaaaaaaa; /* R14 */
            *(--pxTopOfStack) = ( portSTACK_TYPE ) pxOriginalTOS; /* SP */
            *(--pxTopOfStack) = ( portSTACK_TYPE ) 0x12121212; /* R12 */
            .................................................
            *(--pxTopOfStack) = ( portSTACK_TYPE ) pvParameters; /* R0 */
            *(--pxTopOfStack) = ( portSTACK_TYPE ) portINITIAL_SPSR; /* CPSR */
            *(--pxTopOfStack) = portNO_CRITICAL_SECTION_NESTING; /* ulCriticalNesting */

            return pxTopOfStack;
            }
            3.4 上下文的保存與恢復
            本次移植分別定義了兩個宏來實現上下文的保存和恢復,分別是:portSAVE_CONTEXT()和portRESTORE_CONTEXT()。portSAVE_CONTEXT()宏首先設置R0指向任務的堆棧,接著保存任務的返回地址,然后再保存其他的寄存器和CPSR,以及中斷嵌套計數器。最后把新的棧頂保存在當前的任務控制塊里面。其宏定義如下:
            MACRO
            portSAVE_CONTEXT
            STMDB SP!, {R0} ; 設置R0指向任務堆棧.
            STMDB SP, {SP}^
            SUB SP, SP, #4
            LDMIA SP!, {R0}
            STMDB R0!, {LR}
            MOV LR, R0
            LDMIA SP!, {R0}
            STMDB LR, {R0-LR}^ ;把R0-LR寄存器壓入任務堆棧
            SUB LR, LR, #60
            MRS R0, SPSR ;把SPSR壓入任務堆棧
            STMDB LR!, {R0}
            LDR R0, =ulCriticalNesting ;把中斷嵌套計數器壓入任務堆棧
            LDR R0, [R0]
            STMDB LR!, {R0}
            LDR R1, =pxCurrentTCB ; 存儲當前的任務堆棧棧頂到任務控制塊中
            LDR R0, [R1]
            STR LR, [R0]
            MEND
            利用類似的方法可以實現portRESTORE_CONTEXT()宏,需要注意的是,該宏要嚴格按照保存上下文的相反的順序恢復上下文。
            3.5 啟動任務調度
            操作系統初始化之后,就可以開啟系統時鐘,運行系統內第1個最高優先級的就緒任務。對于第1個執行的任務,不需要進行上下文切換,而只要恢復上下文即可。第一個任務的執行是通過調用匯編函數portRESTORE_CONTEXT()恢復上下文來實現的。啟動任務調度程序代碼如下:
            portBASE_TYPE xPortStartScheduler( void )
            {
            prvSetupTimerInterrupt(); /* 設置并啟動Timer0. */
            vPortStartFirstTask(); /* 啟動第一個任務. */
            return 0;
            }
            3.6 任務切換的實現
            程序中portYIELD()函數的調用,會進行一次任務級的上下文切換。在本次移植中,使用軟件中斷指令SWI是處理器進入管理模式和ARM指令狀態,并使用功能0實現portYIELD()的功能。portYIELD()(功能號0)最終使用程序vPortYieldProcessor實現。vPortYieldProcessor的匯編代碼如下:
            vPortYieldProcessor
            ADD LR, LR, #4
            portSAVE_CONTEXT ; 保存上下文 (宏)
            LDR R0, =vTaskSwitchContext ; 選擇就緒的優先級最高優先級的任務
            MOV LR, PC
            BX R0
            portRESTORE_CONTEXT ; 恢復上下文 (宏)

            3.7 時鐘中斷服務的實現
            當時鐘中斷到來的時,處理器跳轉到相應的時鐘中斷服務程序,時鐘中斷服務程序主要調用vTaskIncrementTick()函數,該處理函數主要處理跟系統時鐘相關的工作,如將時鐘節拍數加1,檢查是否有更高優先級的任務就緒等等。系統時鐘中斷服務程序由vTickISR()函數實現。包括以下步驟:(1)保存上下文。(2)調用vTaskIncrementTick()函數,如果系統的調度策略配置為可搶占調度,則查找最高優先級的就緒任務。(3)清除中斷源,并通知中斷控制器中斷結束。(4)恢復上下文。vTickISR()函數的代碼如下:
            void vTickISR( void )
            {
            portSAVE_CONTEXT(); /* 需要保存上下文 */

            /* 增加xTickCount值,檢查新的xTickCount值是否引起一個延遲周期過期,這個函數調用可導致一個任務變成準備運行. */
            vTaskIncrementTick();

            /*如果是系統配置為可搶占式調度,則檢查是否要上下文切換。如果喚醒的任務比已經中斷的任務有更高優先級,就需要切換 */
            #if configUSE_PREEMPTION == 1
            vTaskSwitchContext();
            #endif
            T0IR= portTIMER_MATCH_ISR_BIT; /* 清除中斷源*/
            VICVectAddr = portCLEAR_VIC_INTERRUPT; /* 通知中斷控制器中斷結束*/
            /*恢復上下文.如果發生了上下文切換,這將恢復要繼續運行的任務的上下文 */
            portRESTORE_CONTEXT();
            }

            4結論
            本文設計并實現了FreeRTOS 5.2.0操作系統到ARM7處理器上的移植。移植程序在福州大學工業控制研究所自行研制的ZD100終端上實現,經該環境的多任務運行結果表明,系統穩定可靠。同時,移植的方法在同類ARM架構的處理器上具有較強的通用性。


            參考文獻

            [1] Richard Barry. Creating a New FreeRTOS.org Port[EB/OL].
            http://www.freertos.org/FreeRTOS-porting-guide.html.2008.1-1
            [2] NXP Semiconductors. LPC2292 USER MANUAL[Z]. 2004.14-77
            [3] 劉濱,王琦,劉麗麗. 嵌入式操作系統FreeRTOS的原理與實現[J]. 單片機與嵌入式系統應用, 2005.7 : 8-11.
            [4] ARM Limited. ARM Developer Suite(Version 1.2).Developer Guide[Z].1999.43-51
            [5] 周立功. ARM嵌入式系統基礎教程[M].北京:北京航空航天大學出版社.2004.30-281

            作者簡介
            黃鵬程,男,1984年出生,福建莆田市人,福州大學數學與計算機科學學院碩士研究生,主要研究的方向:嵌入式系統。<

             
             
               
            《通信市場》 中國·北京·復興路49號通信市場(100036) 點擊查看具體位置
            電話:86-10-6820 7724, 6820 7726
            京ICP備05037146號-8
            建議使用 Microsoft IE4.0 以上版本 800*600瀏覽 如果您有什么建議和意見請與管理員聯系
            欧美成人观看免费全部欧美老妇0