新聞中心

EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 傳統(tǒng)ARM中可嵌套的IRQ程序

傳統(tǒng)ARM中可嵌套的IRQ程序

作者: 時(shí)間:2016-11-09 來(lái)源:網(wǎng)絡(luò) 收藏
傳統(tǒng)ARM中IRQ是作為一種系統(tǒng)異常出現(xiàn)的。對(duì)于ARM核來(lái)說(shuō),有且僅有一個(gè)稱(chēng)為IRQ的系統(tǒng)異常。而ARM對(duì)于IRQ的處理一般通過(guò)異常向量找到IRQ的中斷處理程序。當(dāng)進(jìn)入IRQ中斷處理程序之后,ARM自動(dòng)屏蔽IRQ,也就是說(shuō)在中斷響應(yīng)過(guò)程中是忽略之后到來(lái)的中斷請(qǐng)求的。即使使用了VIC,VIC也僅僅是懸起后來(lái)的中斷請(qǐng)求。也就是說(shuō),傳統(tǒng)ARM的中斷是不可嵌套、不可搶占的。

不過(guò),ARM給了我們一種權(quán)利,那就是在中斷處理程序中可以手動(dòng)打開(kāi)IRQ,這樣在前一個(gè)IRQ響應(yīng)的過(guò)程中,就可以被后來(lái)的中斷所打斷。就給我們提供了一種用軟件解決中斷嵌套的途徑。

本文引用地址:http://butianyuan.cn/article/201611/317863.htm

中斷的過(guò)程我們都十分清楚:保護(hù)現(xiàn)場(chǎng)à響應(yīng)中斷à恢復(fù)現(xiàn)場(chǎng)。ARM對(duì)于每一種異常都有相應(yīng)的堆棧寄存器,且會(huì)自動(dòng)切換,互不影響。所以自然而然地,在嵌套中,我們可以用SP_irq來(lái)保護(hù)現(xiàn)場(chǎng)和恢復(fù)現(xiàn)場(chǎng)。流程如下所示:

1.2.3.4.5.6.7.7.17.27.37.47.57.67.77.87.97.10通過(guò)LR_irq跳轉(zhuǎn)回到7

7.11ARM自動(dòng)從SPSR_irq恢復(fù)CPSR

8.9.10.11.

這樣就實(shí)現(xiàn)了嵌套,而且只要堆棧夠大,可以嵌套很多層。不考慮優(yōu)先級(jí),或者把優(yōu)先級(jí)教給中斷控制器管理,這樣已經(jīng)不錯(cuò)了吧,雖然不愿意這么說(shuō),但是問(wèn)題還是來(lái)了。

在上面的流程中,有一步是根據(jù)中斷號(hào)進(jìn)行中斷服務(wù)。對(duì)于不同的中斷源,我們一般都會(huì)用不同函數(shù)來(lái)寫(xiě)中斷服務(wù),這樣不僅清晰,也利于將不同功能的模塊分割開(kāi)。這樣我們就需要將這步變?yōu)椋焊鶕?jù)中斷號(hào)進(jìn)入服務(wù)子程序。這步中,我們會(huì)牽涉到函數(shù)調(diào)用。在函數(shù)調(diào)用過(guò)程中,一般都會(huì)先將PC保存在LR_irq中,在返回時(shí),再將LR_irq恢復(fù)到PC。這也正是LR的作用所在。

正是這個(gè)事實(shí),導(dǎo)致了問(wèn)題的發(fā)生。想象這種情況:當(dāng)我們進(jìn)入服務(wù)子程序后,此時(shí)LR_irq正是我們程序的返回地址。這時(shí),第二個(gè)中斷到來(lái)了,回憶一下中斷發(fā)生時(shí)ARM自動(dòng)做了什么,ARM將PC保存到了LR_irq中!就這樣,LR_irq被篡改了,因?yàn)槲覀儫o(wú)法預(yù)料到中斷什么時(shí)候到來(lái),我們也就根本無(wú)法保存這個(gè)被篡改的LR_irq。程序響應(yīng)好第二個(gè)中斷后,一路返回到這個(gè)LR_irq,毫無(wú)意外的,就跑飛了。

很掃興吧,不過(guò)我們自然有辦法解決這個(gè)問(wèn)題。辦法就是在進(jìn)入服務(wù)子程序之前,先將系統(tǒng)轉(zhuǎn)換到SVC狀態(tài),這樣,子程序被調(diào)用時(shí)返回地址就會(huì)被保存在LR_svc中,也就不會(huì)再被第二個(gè)中斷所篡改。流程如下,和第一次不同的地方都用紅色標(biāo)注。

1.2.3.4.5.6.7.8.9.9.19.29.39.49.59.69.79.89.99.10關(guān)閉IRQ使能位

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

9.12更改系統(tǒng)狀態(tài)為IRQ

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

9.14通過(guò)LR_irq跳轉(zhuǎn)回到9

9.15ARM自動(dòng)從SPSR_irq恢復(fù)CPSR

10.11.12.13.14.15.

這樣我們既可以用中斷服務(wù)子程序,也不怕LR被篡改了。我們?cè)賮?lái)看一下嵌套過(guò)程中的堆棧使用情況。在進(jìn)入SVC狀態(tài)之前,使用IRQ的堆棧,保存嵌套所需的通用寄存器、LR_irq和SPSR_irq。進(jìn)入SVC狀態(tài)之后,使用SVC堆棧,需要保存調(diào)用函數(shù)規(guī)定的R0-R3,LR_svc。當(dāng)然在中斷服務(wù)例程中,也是使用SVC堆棧。可見(jiàn)兩個(gè)狀態(tài)的堆棧都被使用了。當(dāng)然,因?yàn)橹袛喾?wù)例程使用SVC堆棧,我們也可以考慮將嵌套所需的堆棧也放到SVC中,這樣就不需要IRQ堆棧了。流程上和前面這種方法很相似,只不過(guò)要將保存LR_irq和SPSR_irq的時(shí)間放到進(jìn)入SVC態(tài)之后,方法可以是通過(guò)通用寄存器拷貝。最后也不必再返回IRQ態(tài),可以直接通過(guò)SPSR_svc和LR_svc來(lái)推出中斷處理程序。

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

[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. }



關(guān)鍵詞: ARM可嵌套IRQ程

評(píng)論


技術(shù)專(zhuān)區(qū)

關(guān)閉