<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > ARM處理器架構(gòu)異常/中斷處理

          ARM處理器架構(gòu)異常/中斷處理

          作者: 時間:2016-11-09 來源:網(wǎng)絡(luò) 收藏
          中斷是我們嵌入式開發(fā)很常用到的一種資源和編程手段。這篇文章重點分析arm中斷處理流程。

          本文引用地址:http://www.ex-cimer.com/article/201611/317950.htm

          首先,中斷是異常的一種。當發(fā)生一種異常時,處理器會進入不同的工作模式。ARM的異常和相應(yīng)的模式之間的對應(yīng)關(guān)系見下表:

          當一個異常導(dǎo)致模式的改變時,ARM核自動地:

          1、把cpsr保存到相應(yīng)模式下的spsr

          2、把pc保存到相應(yīng)模式下的lr

          3、設(shè)置cpsr為相應(yīng)異常模式

          4、設(shè)置pc為相應(yīng)異常處理程序的入口地址

          對于IRQ或者FIQ而言,還多一項變化:禁用相關(guān)的中斷IRQ或FIQ,禁止同類型的其他中斷被觸發(fā)。(這也是自動實現(xiàn)的,因此正常情況下,ARM中斷不可嵌套)

          從異常中斷處理程序退出時,需要我們在程序中用軟件實現(xiàn)下面兩個操作:

          1、從spsr_mode中恢復(fù)數(shù)據(jù)到cpsr中

          2、從lr_mode中恢復(fù)內(nèi)容到pc中,返回到異常中斷的指令的下一條政令處執(zhí)行.

          2440默認的有一個異常向量表,即發(fā)生某一個異常后,會根據(jù)異常向量表設(shè)置pc為相應(yīng)的處理函數(shù)入口地址。

          地址

          異常名稱

          指令

          0x00

          復(fù)位異常

          B RestHandler

          0x04

          未定義指令異常

          B HandlerUndef

          0x08

          軟件中斷異常

          B HandlerSWI

          0x0C

          指令預(yù)取異常

          B HandlerPabort

          0x10

          數(shù)據(jù)預(yù)取異常

          B HandlerDabort

          0x14

          保留

          0x18

          IRQ中斷異常

          B HandlerIRQ

          0x1C

          FIQ中斷異常

          B HandlerFIQ

          上表中的 指令都是在2440init.s中的程序表示。

          下面,我們結(jié)合板子自帶的2440test源代碼中的2440init.s中的異常處理,來分析arm中斷處理的實現(xiàn)。

          首先,在2440init.s中有:

          __ENTRYb	ResetHandlerb	HandlerUndef	;handler for Undefined modeb	HandlerSWI	    ;handler for SWI interruptb	HandlerPabort	;handler for PAbortb	HandlerDabort	;handler for DAbortb	.		        ;reservedb	HandlerIRQ	;handler for IRQ interruptb	HandlerFIQ	;handler for FIQ interrupt

          這里就是相應(yīng)的 異常處理向量表。程序正常啟動就跳轉(zhuǎn)到resethandler,如果是發(fā)生中斷就跳轉(zhuǎn)到handlerIRQ。對于handlerIRQ,它是用一個宏實現(xiàn)的。

          MACRO$HandlerLabel HANDLER $HandleLabel$HandlerLabelsub	sp,sp,#4	;decrement sp(to store jump address)stmfd	sp!,{r0}	;PUSH the work register to stack(lr doest push because it return to original address)ldr     r0,=$HandleLabel;load the address of HandleXXX to r0ldr     r0,[r0]	 ;load the contents(service routine start address) of HandleXXXstr     r0,[sp,#4]      ;store the contents(ISR) of HandleXXX to stackldmfd   sp!,{r0,pc}     ;POP the work register and pc(jump to ISR)MEND
          上面是宏的聲明。下面是具體用到宏的地方。

          HandlerFIQ      HANDLER HandleFIQHandlerIRQ      HANDLER HandleIRQHandlerUndef    HANDLER HandleUndefHandlerSWI      HANDLER HandleSWIHandlerDabort   HANDLER HandleDabortHandlerPabort   HANDLER HandlePabort
          上面的這段程序在編譯的時候會被編譯器展開,我們可以將其中的IRQ相關(guān)的展開如下:

          HandlerIRQ HANDLER HandleIRQ 會被下面的代碼段替換:

          HandlerIRQ	sub	sp,sp,#4	;decrement sp(to store jump address)stmfd	sp!,{r0}	;PUSH the work register to stack(lr doest push because it return to original address)ldr     r0,=HandleIRQ   ;load the address of HandleXXX to r0ldr     r0,[r0]	        ;load the contents(service routine start address) of HandleXXXstr     r0,[sp,#4]      ;store the contents(ISR) of HandleXXX to stackldmfd   sp!,{r0,pc}     ;POP the work register and pc(jump to ISR)

          因此,發(fā)生中斷時,就會b HandlerIRQ,跳轉(zhuǎn)到上面的代碼進行執(zhí)行。按照上面的流程,處理器會把HandleIRQ地址中所存儲的數(shù) 付給pc指針,作為下一條指令的地址,然后執(zhí)行。那么HandleIRQ地址中存儲的數(shù)是什么呢?

          在2440init.s中有這樣一段程序:

          ldr r0,=HandleIRQ ;This routine is neededldr r1,=IsrIRQ    ;if there isnt subs pc,lr,#4 at 0x18, 0x1cstr r1,[r0]
          從這里,可以看出,HandleIRQ中存的是IsrIRQ。所以處理器會跳轉(zhuǎn)到isrIRQ中執(zhí)行。

          IsrIRQsub	sp,sp,#4       ;reserved for PCstmfd	sp!,{r8-r9}ldr	r9,=INTOFFSETldr	r9,[r9]ldr	r8,=HandleEINT0add	r8,r8,r9,lsl #2ldr	r8,[r8]str	r8,[sp,#8]ldmfd	sp!,{r8-r9,pc}

          在上面的程序中,INTOFFSET表示的是中斷號對于EINT0的偏移號。這樣計算得到中斷向量號之后,跳轉(zhuǎn)到中斷函數(shù)進行處理。對于,上面的程序奇怪的一點是沒有看到恢復(fù)cpsr和pc指針。因此,可以推斷,對于中斷函數(shù)在ADS中有特殊的聲明方式,如:static void __irq Uart_DMA_ISR(void)。像這種聲明方式,在編譯的時候,編譯器會自動在函數(shù)的末尾添加恢復(fù)cpsr和pc的語句。另外, 寄存器r0-r12也是需要保護的,因為在中斷函數(shù)和原來的上下文中都會用到,所以,我認為 編譯器在中斷處理函數(shù)中對r0-r12也進行了保護和恢復(fù)。

          另外,在ucosII中,對IsrIRQ函數(shù)進行了修改,我們后面再進行分析。

          另外,我們用軟件實現(xiàn)了一套中斷向量表:

          ALIGNAREA RamData, DATA, READWRITE^   _ISR_STARTADDRESS		; _ISR_STARTADDRESS=0x33FF_FF00HandleReset 	#   4HandleUndef 	#   4HandleSWI	#   4HandlePabort    #   4HandleDabort    #   4HandleReserved  #   4HandleIRQ	#   4HandleFIQ	#   4;Dont use the label IntVectorTable,;The value of IntVectorTable is different with the address you think it may be.;IntVectorTable;@0x33FF_FF20HandleEINT0		#   4HandleEINT1		#   4HandleEINT2		#   4HandleEINT3		#   4HandleEINT4_7	#   4HandleEINT8_23	#   4HandleCAM		#   4		; Added for 2440.HandleBATFLT	#   4HandleTICK		#   4HandleWDT		#   4HandleTIMER0 	#   4HandleTIMER1 	#   4HandleTIMER2 	#   4HandleTIMER3 	#   4HandleTIMER4 	#   4HandleUART2  	#   4;@0x33FF_FF60HandleLCD 		#   4HandleDMA0		#   4HandleDMA1		#   4HandleDMA2		#   4HandleDMA3		#   4HandleMMC		#   4HandleSPI0		#   4HandleUART1		#   4HandleNFCON		#   4		; Added for 2440.HandleUSBD		#   4HandleUSBH		#   4HandleIIC		#   4HandleUART0 	#   4HandleSPI1 		#   4HandleRTC 		#   4HandleADC 		#   4;@0x33FF_FFA0
          之前,我們在發(fā)生中斷時,pc指針就跳轉(zhuǎn)到了 HandleIRQ地址中所存儲的數(shù) 出執(zhí)行。也就是說在HandleIRQ中存的是異常處理函數(shù)的入口地址。這就是異常處理向量表的作用。
          所以,我們可以看出,對于2440init.s實現(xiàn)的異常處理,采用的是兩級向量表機制。 第一級向量表是arm核自己實現(xiàn)的,發(fā)生相應(yīng)的異常時,pc指針跳轉(zhuǎn)到0x18地址中存的數(shù),作為入口地址。 第二級向量表是由Handler宏實現(xiàn)的,繼續(xù)跳轉(zhuǎn)到 HandleIRQ地址中存的數(shù),繼續(xù)執(zhí)行。

          而對于IRQ來講,還有第三級的向量表,在IsrIRQ中,又會根據(jù)中斷號,比如uart2的中斷,跳轉(zhuǎn)到 HandleUart2地址中 存的數(shù),繼續(xù)執(zhí)行。

          在2440init.s中,并沒有給HandleUndef等這些地址處賦值,因此,一旦執(zhí)行到,程序就會跑飛。



          評論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();