44B0的向量中断

时间:2021-05-25 19:24:18

44B0的向量

中断响应过程是中断发生后芯片会自动跳转到0x00000018处执行指令

ENTRY

b ResetHandler ; 0x00

b HandlerUndef ; 0x04

b HandlerSWI ; 0x08

b HandlerPabort ; 0x0c

b HandlerDabort ; 0x10

b . ; 0x14

b HandlerIRQ ; 0x18

b HandlerFIQ ; 0x1c

ldr pc,=HandlerEINT0 ; 0x20

ldr pc,=HandlerEINT1

ldr pc,=HandlerEINT2

ldr pc,=HandlerEINT3

ldr pc,=HandlerEINT4567

ldr pc,=HandlerTICK ; 0x34

b .

b .

ldr pc,=HandlerZDMA0 ; 0x40

ldr pc,=HandlerZDMA1

ldr pc,=HandlerBDMA0

ldr pc,=HandlerBDMA1

ldr pc,=HandlerWDT

ldr pc,=HandlerUERR01 ; 0x54

b .

b .

ldr pc,=HandlerTIMER0 ; 0x60

ldr pc,=HandlerTIMER1

ldr pc,=HandlerTIMER2

ldr pc,=HandlerTIMER3

ldr pc,=HandlerTIMER4

ldr pc,=HandlerTIMER5 ; 0x74

b .

b .

ldr pc,=HandlerURXD0 ; 0x80

ldr pc,=HandlerURXD1

ldr pc,=HandlerIIC

ldr pc,=HandlerSIO

ldr pc,=HandlerUTXD0

ldr pc,=HandlerUTXD1 ; 0x94

b .

b .

ldr pc,=HandlerRTC ; 0xa0

b .

b .

b .

b .

b .

b .

ldr pc,=HandlerADC ; 0xb4

根据44b0DATASEET0x18处放置的指令为b HandlerIRQ ; 当程序跳转到这里执行时,芯片在这个地址取到的代码已经被后面程序中的branch instructions取代了,举个例子,如果芯片EINT3发生中断,芯片会跳转到0x18处执行,先在0x18处取指,这时取到的指令已经不是b HandlerIRQb HandlerIRQ已经被芯片自动替换成了ldr pc,=HandlerEINT3,然后芯片再执行此条指令。

ARM7TDMI 在矢量模式下,当从 0X18 地址处取指令时候,中断控制器会在数据总线上加载分支指令,这些分支指令使程序计数器能够对应到每一个中断源的向量地址。这些跳转到每一个中断源向量地址的分支指令由中断控制器产生。 

       例如:假设 EINT0 IRQ 中断,EINT0 的向量地址为:0X20(见向量表),那么中断控制器必须产生0X18---0X20的分支指令。 

       中断控制器产生的机器码为: 0XEA000000。在各个中断源对应的中断向量地址中,存放着跳转到相应中断服务程序的程序代码。在相应向量地址处分支指令的机器代码如下计算: 矢量中断模式的机器指令代码=0XEA000000+((<目标地址>-<向量地址>-0X8)>>2) ,机器代码一般由反汇编后自动产生。 

而非向量中断的代码如下

ENTRY

b ResetHandler ; for debug

b HandlerUndef ; handlerUndef

b HandlerSWI ; SWI interrupt handler

b HandlerPabort ; handlerPAbort

b HandlerDabort ; handlerDAbort

b . ; handlerReserved

b IsrIRQ

b HandlerFIQ

. . . . . .

IsrIRQ

sub sp,sp,#4 ; reserved for PC

stmfd sp!,{r8-r9}

ldr r9,=I_ISPR

ldr r9,[r9]

mov r8,#0x0

0 movs r9,r9,lsr #1

bcs %F1

add r8,r8,#4

b %B0

1 ldr r9,=HandleADC

add r9,r9,r8

ldr r9,[r9]

str r9,[sp,#8]

ldmfd sp!,{r8-r9,pc}

. . . . . .

HandleADC # 4

HandleRTC # 4

HandleUTXD1 # 4

HandleUTXD0 # 4

. . . . . .

HandleEINT3 # 4

HandleEINT2 # 4

HandleEINT1 # 4

HandleEINT0 # 4 ; 0xc1(c7)fff84

当发生中断时,芯片自动跳转到0x18处执行,0x18处指令为b IsrIRQIsrIRQ程序的作用是检查I_ISPR的各位,判断是何种中断发生,然后根据中断的种类跳转到相应的中断服务程序去执行,各种中断服务程序的地址定义如下:

HandleADC # 4

HandleRTC # 4

HandleUTXD1 # 4

HandleUTXD0 # 4

. . . . . .

HandleEINT3 # 4

 

 

值得一提的是在44binit代码中,向量中断跳转到HandlerEINT0处而非向量中断跳转到HandleEINT0,程序利用一个宏将这两个标号等同起来,无论采取向量中断还是非向量中断,无论是跳到HandleEINT0还是HandlerEINT0,得到的效果是一样的 ,都是跳到了中断服务程序的地址去执行。

另外顺便说一下飞利浦的LPC系列ARM芯片的中断的方法,当LPC芯片得到中断信号后,在中断初始化时,程序将中断服务程序的入口地址放到中断向量地址寄存器中,每个中断源有一个中断向量地址寄存器和他相对应,另外还有一个叫做VICVectAddr(0xffff0030)的寄存器,当发生中断时,硬件自动判断该执行哪一个中断,然后将该中断源对应的中断向量地址寄存器中的地址放到寄存器VICVectAddr中。程序中断向量表里的代码为跳转到VICVectAddr中的地址执行。一旦发生中断,自动跳转到VICVectAddr中的地址去执行,因为此时VICVectAddr已经被替换成中断源的中断服务程序地址了。

       上述HandleADC # 4是在数据区中分配4个字节的存储空间,等同于HandleADC FEILD 4,这四个字节的存储空间中存的是中断服务程序的地址。在C语言编写的main程序中,如何将中断服务程序的入口地址放入到这个存储空间中呢?细心的读者可以发现这段数据区的起始地址是_ISR_STARTADDRESS,在MAIN函数中只要让(*(unsigned *)(_ISR_STARTADDRESS+0x74)) =(int)MyIsr(MyIsr是中断服务程序的名称);但是_ISR_STARTADDRESS是一个非定值,这个值只有在连接器连接的时候才赋值,在编译阶段他是个不定值,所以编译的时候会报错。#define _ISR_STARTADDRESS 成一个在SDRAM中的地址值。在本例中是0xc7fff00。

          中断的初始化包括对INTMSK ,INTCON进行初始化,如果是EINT0~7 还需要对PCONG、EXTINT进行初始化,对(*(unsigned *)(_ISR_STARTADDRESS+0x74(或者其他偏移量)))赋值。在中断服务程序结尾要对I_ISPC写数清除INTPND。如果是EINT0~7还要在写I_ISPC之前对EXTINTPND寄存器写数。