新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 傳統ARM中可嵌套的IRQ程序

        傳統ARM中可嵌套的IRQ程序

        作者: 時間:2016-11-09 來源:網絡 收藏
        傳統ARM中IRQ是作為一種系統異常出現的。對于ARM核來說,有且僅有一個稱為IRQ的系統異常。而ARM對于IRQ的處理一般通過異常向量找到IRQ的中斷處理程序。當進入IRQ中斷處理程序之后,ARM自動屏蔽IRQ,也就是說在中斷響應過程中是忽略之后到來的中斷請求的。即使使用了VIC,VIC也僅僅是懸起后來的中斷請求。也就是說,傳統ARM的中斷是不可嵌套、不可搶占的。

        不過,ARM給了我們一種權利,那就是在中斷處理程序中可以手動打開IRQ,這樣在前一個IRQ響應的過程中,就可以被后來的中斷所打斷。就給我們提供了一種用軟件解決中斷嵌套的途徑。

        本文引用地址:http://www.104case.com/article/201611/317863.htm

        中斷的過程我們都十分清楚:保護現場à響應中斷à恢復現場。ARM對于每一種異常都有相應的堆棧寄存器,且會自動切換,互不影響。所以自然而然地,在嵌套中,我們可以用SP_irq來保護現場和恢復現場。流程如下所示:

        1.2.3.4.5.6.7.7.17.27.37.47.57.67.77.87.97.10通過LR_irq跳轉回到7

        7.11ARM自動從SPSR_irq恢復CPSR

        8.9.10.11.

        這樣就實現了嵌套,而且只要堆棧夠大,可以嵌套很多層。不考慮優先級,或者把優先級教給中斷控制器管理,這樣已經不錯了吧,雖然不愿意這么說,但是問題還是來了。

        在上面的流程中,有一步是根據中斷號進行中斷服務。對于不同的中斷源,我們一般都會用不同函數來寫中斷服務,這樣不僅清晰,也利于將不同功能的模塊分割開。這樣我們就需要將這步變為:根據中斷號進入服務子程序。這步中,我們會牽涉到函數調用。在函數調用過程中,一般都會先將PC保存在LR_irq中,在返回時,再將LR_irq恢復到PC。這也正是LR的作用所在。

        正是這個事實,導致了問題的發生。想象這種情況:當我們進入服務子程序后,此時LR_irq正是我們程序的返回地址。這時,第二個中斷到來了,回憶一下中斷發生時ARM自動做了什么,ARM將PC保存到了LR_irq中!就這樣,LR_irq被篡改了,因為我們無法預料到中斷什么時候到來,我們也就根本無法保存這個被篡改的LR_irq。程序響應好第二個中斷后,一路返回到這個LR_irq,毫無意外的,就跑飛了。

        很掃興吧,不過我們自然有辦法解決這個問題。辦法就是在進入服務子程序之前,先將系統轉換到SVC狀態,這樣,子程序被調用時返回地址就會被保存在LR_svc中,也就不會再被第二個中斷所篡改。流程如下,和第一次不同的地方都用紅色標注。

        1.2.3.4.5.6.7.8.9.9.19.29.39.49.59.69.79.89.99.10關閉IRQ使能位

        9.11從SP_svc所指示的堆棧中恢復R0-R3,LR_svc

        9.12更改系統狀態為IRQ

        9.13從SP_irq堆棧中恢復通用寄存器、LR_irq、SPSR_irq

        9.14通過LR_irq跳轉回到9

        9.15ARM自動從SPSR_irq恢復CPSR

        10.11.12.13.14.15.

        這樣我們既可以用中斷服務子程序,也不怕LR被篡改了。我們再來看一下嵌套過程中的堆棧使用情況。在進入SVC狀態之前,使用IRQ的堆棧,保存嵌套所需的通用寄存器、LR_irq和SPSR_irq。進入SVC狀態之后,使用SVC堆棧,需要保存調用函數規定的R0-R3,LR_svc。當然在中斷服務例程中,也是使用SVC堆棧。可見兩個狀態的堆棧都被使用了。當然,因為中斷服務例程使用SVC堆棧,我們也可以考慮將嵌套所需的堆棧也放到SVC中,這樣就不需要IRQ堆棧了。流程上和前面這種方法很相似,只不過要將保存LR_irq和SPSR_irq的時間放到進入SVC態之后,方法可以是通過通用寄存器拷貝。最后也不必再返回IRQ態,可以直接通過SPSR_svc和LR_svc來推出中斷處理程序。

        程序貼在下面,用的是堆棧分開的方法,只是示例。

        [cpp]view plaincopy
        1. __asmvoidIRQ_Handler(void){
        2. PRESERVE8
        3. IMPORThandler1
        4. //STORELR_irq&SPSR_irq
        5. SUBLR,LR,#4
        6. MRSR0,SPSR
        7. STMFDSP!,{R0,LR}
        8. //INTOSVCMODE
        9. MRSR0,CPSR
        10. BICR0,#0x1f
        11. ORRR0,#0x13
        12. MSRCPSR_C,R0
        13. //STOREREGISTORSOFSVCMODE
        14. STMFDSP!,{R0-R3,LR}
        15. //ENABLEIRQ
        16. MRSR0,CPSR
        17. BICR0,#0x80
        18. MSRCPSR_C,R0
        19. //GOTOHANDLER
        20. BLhandler1
        21. //RESTOREREGISTORSOFSVCMODE
        22. LDMFDSP!,{R0-R3,LR}
        23. //DISABLEIRQ
        24. MRSR0,CPSR
        25. ORRR0,#0x80
        26. MSRCPSR_C,R0
        27. //INTOIRQMODE
        28. MRSR0,CPSR
        29. BICR0,#0x1f
        30. ORRR0,#0x12
        31. MSRCPSR_C,R0
        32. //RESTORELR_irq&SPSR_irq
        33. LDMFDSP!,{R0,LR}
        34. MSRSPSR_CFX,R0
        35. //EXITIRQ
        36. MOVSPC,LR
        37. }



        關鍵詞: ARM可嵌套IRQ程

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 巩义市| 青神县| 略阳县| 汝阳县| 岳阳市| 正定县| 凉山| 灵石县| 苗栗市| 江永县| 蒲城县| 长春市| 宜宾市| 中西区| 壶关县| 平安县| 陇南市| 绍兴市| 南康市| 孟州市| 靖安县| 阳山县| 安丘市| 亳州市| 黄浦区| 汪清县| 育儿| 平罗县| 阳信县| 靖宇县| 屏东市| 九龙县| 宜阳县| 房产| 无棣县| 临潭县| 德化县| 堆龙德庆县| 英吉沙县| 沛县| 台前县|