www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁 > 嵌入式 > 嵌入式硬件
[導(dǎo)讀]摘要:在μC/OS-II內(nèi)核中,各個不同的任務(wù)使用獨立的堆??臻g,堆棧的大小按每個任務(wù)所需要的最大堆棧深度來定義,這種方法可能會造成堆??臻g浪費。本文敘述如何在RTOS中

摘要:在μC/OS-II內(nèi)核中,各個不同的任務(wù)使用獨立的堆棧空間,堆棧的大小按每個任務(wù)所需要的最大堆棧深度來定義,這種方法可能會造成堆??臻g浪費。本文敘述如何在RTOS中多個任務(wù)共用連續(xù)存儲空間作為任務(wù)棧的方法,并詳細比較二者的優(yōu)缺點和適用性。 關(guān)鍵詞:μC/OS-II 任務(wù)堆棧 RTOS 共用空間堆棧 關(guān)于μC/OS-II這個實時內(nèi)核及其應(yīng)用已經(jīng)有很多文章介紹了,對于學(xué)習(xí)RTOS的人來說,這個系統(tǒng)是很好的學(xué)習(xí)起點。雖然文獻[1]的源代碼沒有行號和函數(shù)名交叉索引表等,給源代碼閱讀造成一些困難(可使用BC31的grep查找功能,提高閱讀效率),好在代碼不是很長,前面又有詳細的中文說明,對于有一定X86匯編和C語言基礎(chǔ)的人來說,仍然可以在不長的時間內(nèi)掌握。 μC/OS-II內(nèi)核是一個搶先式內(nèi)核,可以進行任務(wù)間切換,也可以讓一個任務(wù)在得不到某個資源時休眠一定時間后再繼續(xù)運行;提供了用于共享資源管理的信號燈,用于進程通信的消息隊列和郵箱,甚至提供了存儲器管理機制,一個比較全面的系統(tǒng)。 μC/OS-II內(nèi)核有些地方仍然值得改進,比如該系統(tǒng)不支持時間片調(diào)度。如果有一個任務(wù)中一段死循環(huán)代碼(或者條件循環(huán)代碼),代碼就會永遠(或長時間)在此處執(zhí)行,調(diào)度程序無法控制,其它任務(wù)也就是不到及時執(zhí)行。這種搶先式實際上和非搶先式系統(tǒng)存在著同樣問題。當(dāng)然,如果這種代碼不一個BUG,問題是可以解決的,在不提供時間片調(diào)度的搶先式系統(tǒng)中,一般采取信號燈,或者任務(wù)主動休眠的方法(對于μC/OS-II,很容易改造成支持時間片調(diào)度,只要在定時中斷服務(wù)程序調(diào)用OSIntCtxSw()函數(shù)即可);非搶先式系統(tǒng)一般采取有限狀態(tài)機方法,不使用這種耗時很長的循環(huán)代碼。不過,無論如何,對 RTOS的使用者來說,這畢竟會使得任務(wù)函數(shù)的編碼不能隨心所欲。 ΜC/OS-II內(nèi)核的另外一個值得改進的地方就是其任務(wù)棧管理方法。在μC/OS-II內(nèi)核中,各個不同的任務(wù)使用獨立的堆??臻g,堆棧的大小按每個任務(wù)所需要的最大堆棧深度來定義,這種方法可能會造成堆??臻g的浪費。下面討論如何在RTOS中多個任務(wù)共用一段連續(xù)存儲空間作為傻堆棧。

1 任務(wù)切換要保存的數(shù)據(jù) 簡單地說,一個任務(wù)可看作一個運行中的C函數(shù)。對于搶先式RTOS來說,在任務(wù)切換時,應(yīng)保存當(dāng)前任務(wù)的各種現(xiàn)場數(shù)據(jù)。現(xiàn)場數(shù)據(jù)包括局部變量、各個CPU 寄存器、堆棧指針和程序被中止的任務(wù)指針。CPU寄存器是任何任務(wù)代碼均會用到的;而局部變量,一般的編譯器是將其它安排在堆??臻g中,堆棧指針也是各任務(wù)公用的,所以也需要保存。 對于全局變量,由于一般是在內(nèi)存中的固定位置,各任務(wù)所占用的空間完全獨立,所以不需要保存。 在X86環(huán)境中,要保存的CPU寄存器共14個16位寄存器;通用寄存器8個(AX、BX、CX、DX、SP、BP、SI、BI)、段寄存器4個(CS、 DS、ES、SS)以及指令指針I(yè)P和標志寄存器FR各1個。 2 C編譯器中變量在堆棧中的位置 對于一個存在函數(shù)調(diào)用嵌套的C程序來說,大部分編譯器將傳遞的參數(shù)和函數(shù)本身的局部變量放在了堆棧中,編譯器會自動生成壓棧(push)和彈棧(pop)代碼,以保存上級函數(shù)的運行寄存器。 假設(shè)函數(shù)main()調(diào)用funl(),而funl()調(diào)用fun2(),則在執(zhí)行fun2()中的代碼時,堆棧映像如圖1所示(X86 CPU的情況)。 對于RTOS軟件,堆棧中的各種數(shù)據(jù)就是一個任務(wù)的作現(xiàn)場。一般CPU的堆棧指針SP只有一個,在進行任務(wù)切換時,必須將掛起任務(wù)所使用的堆棧內(nèi)容保存起來,以便使該任務(wù)在下次喚醒時能從原地繼續(xù)運行。 3 μC/OS-II對任務(wù)棧的處理方法與缺陷 μC/OS-II為了保存任務(wù)堆棧中的數(shù)據(jù),對每個任務(wù)定義一個數(shù)組變量作為堆棧,在任務(wù)切換時,將CPU堆棧指針SP指向該數(shù)組中的某個元素,即棧頂,如圖2所示。 比如,在其ex21.c文件中定義的任務(wù)堆棧語句為: OS_STK TaskStartStk[TASK_STK_SIZE]; /*啟動任務(wù)堆棧*/ OS_STK TaskClkStk[TASK_STK_SIZE]; /*時鐘任務(wù)堆棧*/ OS_STK TasklStk[TASK_STK_SIZE]; /*任務(wù)1#,任務(wù)堆棧*/ …… 以上各任務(wù)堆棧數(shù)組變量在初始化函數(shù)OSTCBInit()中被會給了任務(wù)控制塊OS_TCB的OSTCBStkPtr變量。在任務(wù)切換時,μC/OS- II調(diào)用OSCtxSw匯編過程(OS_CPU_A.ASM文件),將CPU的SP指針指向該變量,從而使每個任務(wù)使用獨立的任務(wù)堆棧。 LES BX,DWORD PTR DS:_OSTCBCur ;保存掛起任務(wù)的堆棧指針SP MOV ES:[BX+2],SS MOV ES:[BX+0],SP …… LESB X,DWORD PTR DS:_OSTCBHighRdy ;切換SP到要運行任務(wù)的堆棧空間 MOV SS,ES:[BX+2] MOV SP,ES:[BX] ……

在代碼中,變量OSTCBHighRdy(OSTCBCur)和堆棧指針變量OSTCBStkPtr的數(shù)值是同同的,因為OSTCBStkPtr是結(jié)構(gòu) OSTCBHighRdy的第一個變量。 這種任務(wù)棧處理方法的缺點是可能造成空間的浪費。因為一個任務(wù)如果堆棧滿了,該任務(wù)也就無法運行,即使其它任務(wù)的堆棧還有空間可用。當(dāng)然,這種方法的好處是任務(wù)棧切換的時間非常短,只需要幾條指令。 4 共用空間的堆棧處理方法 (1)棧共用連續(xù)存儲空間 如果多個任務(wù)使用同一段連續(xù)空間作為堆棧,這樣各個堆棧之間就可以互補使用。在前面說過,共用空間的問題在于一個任務(wù)運行時不能破壞其它任務(wù)的堆棧數(shù)據(jù)。為簡單起見,先看圖3所示兩個任務(wù)的情況。 假定任務(wù)1首次運行時任務(wù)棧為空。運行一段時間后任務(wù)2運行,堆棧空間繼續(xù)往上生長。這次任務(wù)切換不需要修改CPU的SP數(shù)值,但需要記下任務(wù)1的棧頂位置SP1(圖3中)。 在任務(wù)2運行一段時間后,RTOS又切換到任務(wù)1運行。在切換時,不能簡單地將SP指針修改回SP1的數(shù)值,因為這樣堆棧向上生長時會破壞任務(wù)2堆棧中的數(shù)據(jù)。辦法是將原來任1務(wù)堆棧保存的數(shù)據(jù)移動到靠棧頂?shù)奈恢?,而將任?wù)2堆棧數(shù)據(jù)下移到靠棧底的位置,堆棧指針SP實際上不需要修改(圖3右)。 考慮到更為一般的情況,有N個任務(wù),當(dāng)前運行的任務(wù)為k,下一個運行的任務(wù)為j,在共用任務(wù)堆棧時必須做的工作有: *為每個任務(wù)定義棧頂和棧底2個堆棧指針; *在任務(wù)切換時,將待運行任務(wù)j的堆棧內(nèi)容移動到靠棧頂位置,同時將其堆棧上方的任務(wù)堆棧下移,修改被移動推棧的任務(wù)堆棧指針。 假設(shè)我們定義的任務(wù)??臻g和任務(wù)的棧指針變量為: void TaskSTK[MAX_STK_LEN];/*任務(wù)堆??臻g*/ typedef struct TaskSTKPoint{ int TaskID; int pTopSTK; int pBottomSTK; }TASK_STK_POINT; TASK_STK_POINT pTaskSTK[MAX_TASK_NUM]; /*存放每個任務(wù)的棧頂和棧底指針*/ 任務(wù)棧指針數(shù)組pTaskSTK的元素個數(shù)同任務(wù)個數(shù)。為了堆棧交換,需要另外一塊臨時存儲空間,其大小可按單個任務(wù)棧最大長度定義,用于中轉(zhuǎn)堆棧交換的內(nèi)容。堆棧內(nèi)容交換的偽C算法可寫為: StkEechange(int CurTaskID,int RunTaskID) { /*2個參數(shù)為當(dāng)前運行任務(wù)號和下一運行任務(wù)號*/ void TempSTK[MAX_PER_STK_LEN]; /*注意該變量長度可小于TaskSTK*/ L=任務(wù)RunTaskTD的堆棧長度; ①將TaskSTK頂部的L字節(jié)移動到TempSTK中; ②將RunTaskID任務(wù)的堆棧內(nèi)容移動到TaskSTK頂部; ③將RunTaskID堆棧上方(移動前位置)所有內(nèi)容下移L個字節(jié); ④修改RunTask堆棧上方(移動前位置)所有任務(wù)棧頂和棧底指針(pTaskSTK變量); };[!--empirenews.page--]

該算法的平均時間復(fù)雜度可計算如下: O(T)=SL/2+SL/2+SL%26;#215;N/2 式中,第一、二項為步驟①和步驟②時間,第三項為步驟③時間;SL表示每個任堆棧的最大長度(即MAX_PER_STK_LEN),N表示任務(wù)數(shù)。 取SL為64字節(jié),任務(wù)數(shù)為16個,則數(shù)據(jù)項平均移動次數(shù)為576。假設(shè)每次移動指令時間為2μs,則一次任務(wù)棧移動時間長達約1ms。所以在使用該方法時,為了執(zhí)行時間盡量短,編碼時應(yīng)仔細推敲。 從空間上說,共用任務(wù)棧比獨立任務(wù)棧優(yōu)越。假設(shè)獨立任務(wù)棧方法中每個堆??臻g為K,任務(wù)數(shù)為N,則獨立任務(wù)棧方式的堆??偪臻g為N%26;#215;K。在共用任務(wù)棧時,考慮各任務(wù)互補的情況,TaskSTK變量不需要定義為N%26;#215;K長度,可能定義為二分之一或者更小就可以了。 另外,這種方法不需要在任務(wù)切換時修改CPU的SP指針。 (2)工作棧和任務(wù)堆棧 上節(jié)共用任務(wù)棧算法的缺點是:任務(wù)切換時的堆棧內(nèi)容交換算法復(fù)雜,占用時間長。另外一個折中的方法是設(shè)計一個工作堆棧,用于給當(dāng)前運行的任務(wù)使用;在任務(wù)切換時,將工作棧內(nèi)容換出得另外的存儲空間,該空間可以動態(tài)申請,其大小按實際需要即可。 這種方法看起來和獨立任務(wù)棧的方法類似,需要N+1塊存儲空間,其中一塊用于工作??臻g。和獨立任務(wù)堆棧相比,其區(qū)別有2點: ①SP指針所指向的空間始終是同一塊存儲空間,即工作棧; ②每個任務(wù)棧的大小不需要按最大空間定義,可以動態(tài)按實際大小從內(nèi)存中分配空間。 對于8031這種處理器結(jié)構(gòu),由于堆棧指針只能指向其內(nèi)部存儲器,大小十分有限。采取這種方法,可將工作棧設(shè)在內(nèi)部RAM,將任務(wù)棧設(shè)在外部RAM,擴展了堆??臻g。 和上一種共用堆棧方法相比,這種方法的交換時間要短,其時間復(fù)雜度約為1.5倍最大任務(wù)棧長度。 5 總結(jié) 獨立任務(wù)棧的方法適合于存儲器充足、任務(wù)切換頻繁、對任務(wù)切換時間要求較高的場合,一般主要用在16位或者32位微處理器平臺環(huán)境。值得注意的是,在某些微處理器中,雖然可使用的數(shù)據(jù)存儲器可以設(shè)計得較大,但堆棧所能使用的存儲器卻是有限的。比如8031系列存儲器,堆棧只能使用內(nèi)部的128字節(jié)數(shù)據(jù)存儲器,即使系統(tǒng)中有64K字節(jié)的外部數(shù)據(jù)存儲器,任務(wù)棧的總空間也不能超過128字節(jié)。這種處理器使用共用任務(wù)棧結(jié)構(gòu)的RTOS就更好一些。 由于共用任務(wù)棧系統(tǒng)需要較長的任務(wù)切換時間,不適于任務(wù)切換頻繁的場合,在很多嵌入式系統(tǒng)中,長時間只有幾個任務(wù)會處于運行狀態(tài),其它任務(wù)在特定的條件下才會運行。對于RTOS的使用者,也可以適當(dāng)?shù)貏澐秩蝿?wù),來減小任務(wù)切換的時間。 無論使用哪種方法,在存儲空間有限時,任務(wù)棧的長度應(yīng)仔細計算。計算的根據(jù)是任務(wù)中的函數(shù)嵌套數(shù)、函數(shù)局部變量長度。對于共用任務(wù)棧,還要考慮同時運行態(tài)和掛起態(tài)的最大任務(wù)數(shù)。一些編譯器可以生成堆棧溢出檢查代碼,在調(diào)試時可將該編譯開關(guān)打開,以測試需要的實際堆棧長度。

本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

在嵌入式系統(tǒng)和底層驅(qū)動開發(fā)中,C語言因其高效性和可控性成為主流選擇,但缺乏原生單元測試支持成為開發(fā)痛點。本文提出一種基于宏定義和測試用例管理的輕量級單元測試框架方案,通過自定義斷言宏和測試注冊機制,實現(xiàn)無需外部依賴的嵌入...

關(guān)鍵字: C語言 嵌入式系統(tǒng) 驅(qū)動開發(fā)

在Linux設(shè)備驅(qū)動開發(fā)中,等待隊列(Wait Queue)是實現(xiàn)進程睡眠與喚醒的核心機制,它允許進程在資源不可用時主動放棄CPU,進入可中斷睡眠狀態(tài),待資源就緒后再被喚醒。本文通過C語言模型解析等待隊列的實現(xiàn)原理,結(jié)合...

關(guān)鍵字: 驅(qū)動開發(fā) C語言 Linux

在數(shù)字化時代,電子墨水屏(E-Ink)因其獨特的顯示效果和低功耗特性,在電子書、智能手寫本等領(lǐng)域得到了廣泛應(yīng)用。然而,電子墨水屏的刷新率一直是其發(fā)展的瓶頸,如何在保證低功耗的同時提高刷新率,成為了驅(qū)動開發(fā)中的一個重要課題...

關(guān)鍵字: 電子墨水屏 E-Ink 驅(qū)動開發(fā)

在Linux驅(qū)動開發(fā)中,設(shè)備樹(Device Tree)作為一種描述硬件信息的數(shù)據(jù)結(jié)構(gòu),扮演著至關(guān)重要的角色。它使得操作系統(tǒng)能夠以一種更加靈活和標準化的方式識別和管理硬件設(shè)備。然而,在實際的開發(fā)過程中,設(shè)備樹配置錯誤或理...

關(guān)鍵字: Linux 驅(qū)動開發(fā) Debug

在嵌入式系統(tǒng)與設(shè)備驅(qū)動開發(fā)的廣闊領(lǐng)域中,時鐘、定時器以及延時函數(shù)扮演著至關(guān)重要的角色。它們不僅是系統(tǒng)時間管理的基石,更是實現(xiàn)高效、精確控制硬件行為的關(guān)鍵工具。本文將深入探討這三種機制在驅(qū)動開發(fā)中的具體應(yīng)用、實現(xiàn)方式及注意...

關(guān)鍵字: 驅(qū)動開發(fā) 嵌入式系統(tǒng) 延時函數(shù)

在Linux內(nèi)核的廣闊領(lǐng)域中,驅(qū)動開發(fā)是連接硬件與軟件、實現(xiàn)設(shè)備功能的關(guān)鍵環(huán)節(jié)。在這個過程中,文件操作函數(shù)與I/O操作函數(shù)作為兩大核心工具,各自扮演著不可或缺的角色。本文旨在深入探討這兩種函數(shù)在Linux驅(qū)動開發(fā)中的區(qū)別...

關(guān)鍵字: I/O操作函數(shù) 文件操作函數(shù) Linux 驅(qū)動開發(fā)

史勝輝,在MTK工作了11年,一直在基帶芯片的USB驅(qū)動領(lǐng)域做開發(fā)和驗證。從最開始做USB2.0/3.0 IP驗證和驅(qū)動開發(fā)到后面帶領(lǐng)團隊做上層協(xié)議驅(qū)動開發(fā),以及跟硬件設(shè)計部門合作開發(fā)全新的USB硬件加速器。

關(guān)鍵字: 基帶芯片 驅(qū)動領(lǐng)域 驅(qū)動開發(fā)

摘要:闡述了煤礦人員定位系統(tǒng)網(wǎng)絡(luò)中識別卡的工作原理,分析了定位識別卡在實際工作中呼叫功能受限的主要原因,并在此基礎(chǔ)上,提出了一種對定位識別卡結(jié)構(gòu)進行改進的實現(xiàn)方法。經(jīng)在煤礦井下對改進后的系統(tǒng)進行的多次實驗證明,其識別效果...

關(guān)鍵字: 識別卡 煤礦呼叫 人員定位 改進方法

點擊上方名片關(guān)注我們朱老師推薦語:此崗位為AIoT終身成長大會員同學(xué)提供的自己公司的崗位內(nèi)推,總部在深圳,是一家專業(yè)從事閉路電視監(jiān)控設(shè)備、會議攝像機的研發(fā)、制造、銷售的高科技企業(yè),有學(xué)過嵌入式課程或者海思項目的同學(xué),想換...

關(guān)鍵字: 開發(fā)工程師 linux驅(qū)動 驅(qū)動開發(fā)

最近在學(xué)習(xí)MIPI接口的LCD驅(qū)動開發(fā)與調(diào)試,這里我主要用的是MIPI-DSI接口,它學(xué)習(xí)起來真的是太復(fù)雜了,特別是對于我這種很久都沒寫驅(qū)動來說更是頭疼,但是頭疼歸頭疼,工作咱們還是要完成的,那就只能硬著頭皮往下肝吧!首...

關(guān)鍵字: MIPI 驅(qū)動開發(fā) 調(diào)試
關(guān)閉