您的位置:首页 > 其它

ARM异常---一个Uart中断的触发处理过程:

2016-07-31 12:35 471 查看
首先给出一些定义:

//2440addr.inc

INTOFFSET    EQU  0x4a000014    ;Interruot request source offset


//option.inc

_ISR_STARTADDRESS    EQU 0x33ffff00


//2440init.s

MACRO
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel
sub        sp,sp,#4            ;decrement sp(to store jump address)
stmfd    sp!,{r0}            ;PUSH the work register to stack(lr does t push because it return to original address)
ldr     r0,=$HandleLabel    ;load the address of HandleXXX to r0
ldr     r0,[r0]                 ;load the contents(service routine start address) of HandleXXX
str     r0,[sp,#4]          ;store the contents(ISR) of HandleXXX to stack
ldmfd   sp!,{r0,pc}         ;POP the work register and pc(jump to ISR)
MEND


下面进入正题:

//2440init.s

PRESERVE8
AREA    RESET,CODE,READONLY
ENTRY
EXPORT    __ENTRY
__ENTRY
ResetEntry
b    ResetHandler    ;0x0
b    HandlerUndef    ;handler for Undefined mode
b    HandlerSWI       ;handler for SWI interrupt
b    HandlerPabort    ;handler for PAbort
b    HandlerDabort    ;handler for DAbort
b    .                       ;reserved
b    HandlerIRQ        ;handler for IRQ interrupt
b    HandlerFIQ        ;handler for FIQ interrupt
b    EnterPWDN        ; Must be @0x20.

...

HandlerIRQ      HANDLER HandleIRQ

...

.............
; Setup IRQ handler//建立中断表
ldr    r0,=HandleIRQ       ;This routine is needed
ldr    r1,=IsrIRQ      ;if there isn t 'subs pc,lr,#4' at 0x18, 0x1c
str    r1,[r0]

................
^   _ISR_STARTADDRESS        ;0x33ffff00
HandleReset     #   4
HandleUndef     #   4
HandleSWI        #   4
HandlePabort    #   4
HandleDabort    #   4
HandleReserved  #   4
HandleIRQ        #   4
HandleFIQ        #   4            ;0x33ffff1C
;IntVectorTable
;@0x33FF_FF20
HandleEINT0        #   4            ;0x33ffff20
HandleEINT1        #   4
HandleEINT2        #   4
.................................
HandleUART1        #   4            ;0x33ffff7C
.................................


uart是一个外部中断,走的是FIQ.

外部中断 --> b HandlerFIQ ;

  看代码发现HandlerFIQ在init.s中进行了宏定义,展开之后得到:

//展开宏 HandlerIRQ  HANDLER  HandleIRQ
HandlerIRQ
sub        sp,sp,#4          ;decrement sp(to store jump address)
stmfd    sp!,{r0}            ;PUSH the work register to stack(lr does t push because it return to original address)
ldr     r0,=$HandleIRQ       ;load the address of HandleXXX to r0
ldr     r0,[r0]              ;load the contents(service routine start address) of HandleXXX
str     r0,[sp,#4]           ;store the contents(ISR) of HandleXXX to stack
ldmfd   sp!,{r0,pc}          ;POP the work register and pc(jump to ISR)


  可以看到,HandlerIRQ是一个标准的中断处理过程(正因如此使用了宏进行封装): 首先保存现场,然后跳转到HandleIRQ,从HandleIRQ回来之后恢复现场.

  HandleIRQ其实是一个函数指针,它可以在程序中被我们指向某一个处理函数. 这里我们指向了IsrIRQ. 在IsrIRQ里,我们读取INTOFFSET寄存器的值,加上外部中断的起始值HandleEINT0,这样我们就获得了世纪的中断入口HandleUART1. 通过ldmfd sp!,{r8-r9,pc},我们跳转进入了HandleUART1对应的实际的中断处理函数(见后面的分析).

//2440init.s
IsrIRQ
 sub        sp,sp,#4       ;reserved for PC
stmfd    sp!,{r8-r9}
ldr        r9,=INTOFFSET
ldr        r9,[r9]
ldr        r8,=HandleEINT0
add        r8,r8,r9,lsl #2  ;//r8=r8+(r9*4)
ldr        r8,[r8]
str        r8,[sp,#8]
 ldmfd    sp!,{r8-r9,pc}


  上面说到,"通过ldmfd sp!,{r8-r9,pc},我们跳转进入了HandleUART1对应的实际的中断处理函数." 怎么跳转的呢,在代码里,我们又实现并绑定了HandleUART1的处理函数Uart1_TxRxInt:

//2440addr.h
#define pISR_UART1        (*(unsigned *)(_ISR_STARTADDRESS+0x7c))

//2440lib.c
pISR_UART1=(unsigned)Uart1_TxRxInt;
extern unsigned char UartBuf1[256];

void __irq Uart0_TxRxInt(void)//这里只处理了接收中断
{
unsigned char *pbuf = UartBuf1;
if(rSUBSRCPND & BIT_SUB_RXD0)  //接收中断
{
rINTSUBMSK |= BIT_SUB_RXD0;

while((rUFSTAT0&0x3f))
{
*pbuf++ = rURXH0;
}
*pbuf = '\0';

rINTSUBMSK &= ~BIT_SUB_RXD0;
rSRCPND |= BIT_UART0;
rINTPND |= BIT_UART0;
rINTSUBMSK &= ~(BIT_SUB_TXD0);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: