新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > ARM处理器架构异常/中断处理

ARM处理器架构异常/中断处理

作者: 时间:2016-11-09 来源:网络 收藏
中断是我们嵌入式开发很常用到的一种资源和编程手段。这篇文章重点分析arm中断处理流程。

本文引用地址:https://www.eepw.com.cn/article/201611/317950.htm

首先,中断是异常的一种。当发生一种异常时,处理器会进入不同的工作模式。ARM的异常和相应的模式之间的对应关系见下表:

当一个异常导致模式的改变时,ARM核自动地:

1、把cpsr保存到相应模式下的spsr

2、把pc保存到相应模式下的lr

3、设置cpsr为相应异常模式

4、设置pc为相应异常处理程序的入口地址

对于IRQ或者FIQ而言,还多一项变化:禁用相关的中断IRQ或FIQ,禁止同类型的其他中断被触发。(这也是自动实现的,因此正常情况下,ARM中断不可嵌套)

从异常中断处理程序退出时,需要我们在程序中用软件实现下面两个操作:

1、从spsr_mode中恢复数据到cpsr中

2、从lr_mode中恢复内容到pc中,返回到异常中断的指令的下一条政令处执行.

2440默认的有一个异常向量表,即发生某一个异常后,会根据异常向量表设置pc为相应的处理函数入口地址。

地址

异常名称

指令

0x00

复位异常

B RestHandler

0x04

未定义指令异常

B HandlerUndef

0x08

软件中断异常

B HandlerSWI

0x0C

指令预取异常

B HandlerPabort

0x10

数据预取异常

B HandlerDabort

0x14

保留

0x18

IRQ中断异常

B HandlerIRQ

0x1C

FIQ中断异常

B HandlerFIQ

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

下面,我们结合板子自带的2440test源代码中的2440init.s中的异常处理,来分析arm中断处理的实现。

首先,在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

这里就是相应的 异常处理向量表。程序正常启动就跳转到resethandler,如果是发生中断就跳转到handlerIRQ。对于handlerIRQ,它是用一个宏实现的。

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相关的展开如下:

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)

因此,发生中断时,就会b HandlerIRQ,跳转到上面的代码进行执行。按照上面的流程,处理器会把HandleIRQ地址中所存储的数 付给pc指针,作为下一条指令的地址,然后执行。那么HandleIRQ地址中存储的数是什么呢?

在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。所以处理器会跳转到isrIRQ中执行。

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的偏移号。这样计算得到中断向量号之后,跳转到中断函数进行处理。对于,上面的程序奇怪的一点是没有看到恢复cpsr和pc指针。因此,可以推断,对于中断函数在ADS中有特殊的声明方式,如:static void __irq Uart_DMA_ISR(void)。像这种声明方式,在编译的时候,编译器会自动在函数的末尾添加恢复cpsr和pc的语句。另外, 寄存器r0-r12也是需要保护的,因为在中断函数和原来的上下文中都会用到,所以,我认为 编译器在中断处理函数中对r0-r12也进行了保护和恢复。

另外,在ucosII中,对IsrIRQ函数进行了修改,我们后面再进行分析。

另外,我们用软件实现了一套中断向量表:

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
之前,我们在发生中断时,pc指针就跳转到了 HandleIRQ地址中所存储的数 出执行。也就是说在HandleIRQ中存的是异常处理函数的入口地址。这就是异常处理向量表的作用。
所以,我们可以看出,对于2440init.s实现的异常处理,采用的是两级向量表机制。 第一级向量表是arm核自己实现的,发生相应的异常时,pc指针跳转到0x18地址中存的数,作为入口地址。 第二级向量表是由Handler宏实现的,继续跳转到 HandleIRQ地址中存的数,继续执行。

而对于IRQ来讲,还有第三级的向量表,在IsrIRQ中,又会根据中断号,比如uart2的中断,跳转到 HandleUart2地址中 存的数,继续执行。

在2440init.s中,并没有给HandleUndef等这些地址处赋值,因此,一旦执行到,程序就会跑飞。



评论


技术专区

关闭