arm7 LPC2103 中断的处理方法

        向量中断控制器(VIC)具 有 32 个中断请求输入,可将其编程分为3 类:FIQ 、向量IRQ和非向量IRQ 。可编程分配机制意味着不同外设的中断优先级可以动态分配并调整。
快速中断请求(FIQ )要求具有最高优先级。如果分配给 FIQ 的请求多于1 个,VIC 将中断请求“相或”后向ARM处理器产生 FIQ 信号。当只有一个中断被分配为 FIQ 时可实现
最短的FIQ 等待时间,因为FIQ 服务程序只要简单地启动器件的处理就可以了。但如果分配给FIQ 级的中断多于1 个,FIQ 服务程序从 VIC 中读出一个字来识别产生中断请求的 FIQ中断源是哪一个。

        向量IRQ 具有中等优先级。该级别可分配32 个请求中的 16 个。32个请求中的任意一个都可分配到16 个向量IRQ slot 中的任意一个,其中 slot0 具有最高优先级,而 slot15 则为最低优先级。

        非向量IRQ 的优先级最低。VIC 将所有向量和非向量IRQ “相或”向 ARM处理器产生IRQ 信号。IRQ 服务程序可通过读取VIC 的一个寄存器立即启动并跳转到相应地址。如果有任意一个向量IRQ 发出请求,VIC 则提供最高优先级请求IRQ 服务程序的地址,否则提供所默认程序的地址。该默认程序由所有非向量IRQ 共用。默认程序可读取另一个VIC 寄存器以确定哪个IRQ 被激活。


一、向量中断

1.1 第一种方法,每次中断都可以直接跳转到对应的中断处理函数

1.1.1 启动代码
        ARM
__vector:
        ;;
        ldr   pc,[pc,#+24]              ;; Reset
        ldr   pc,[pc,#+24]              ;; Undefined instructions
        B   .                           ;; Software interrupt (SWI/SVC)
        ldr   pc,[pc,#+24]              ;; Prefetch abort
        ldr   pc,[pc,#+24]              ;; Data abort
__vector_0x14:
        DC32  0                         ;; RESERVED
        ldr   pc,[pc,#-0xFF0]           ;; IRQ
        ldr   pc,[pc,#+24]              ;; FIQ

        DC32  __iar_program_start       ;; Reset
        DC32  undef_handler             ;; Undefined instructions
        DC32  0                         ;; Software interrupt (SWI/SVC)
        DC32  prefetch_handler          ;; Prefetch abort
        DC32  data_handler              ;; Data abort
        DC32  0                         ;; RESERVED
        DC32  0                         ;; IRQ
        DC32  fiq_handler               ;; FIQ
    这里FIQ很好理解,但这里的IRQ为什么要PC-0XFF0呢?

     结合ARM7的三级流水线,这个问题应该就很简单了,当程序跳到0X18执行指令的时候,PC应该是0x18+8=0x20,
     然后0x20-0xff0=0xfffff030,此处0XFFFFF030正好是 VICVectAddr 的地址,意思就是通过一条简单的ARM指令,
     实现了IRQ的程序跳转

1.1.2 初始化,以串口中断为例
设置 0号 IRQ slot (向量中断中优先级最高)为串口中断,并且把 中断处理函数 IRQ_UART_0 赋给 VICVectAddr0
void Init_uart0()
{
    U0LCR = 0x83; //使能访问除数寄存器,8位字符长度     
    U0DLM = 0x00; //115200时为6   9600时为0x006c
    U0DLL = 0x6c;
    U0LCR = 0x03; //禁止访问除数寄存器       
    U0IER = 0x03; //允许接收数据可用中断[第0位]和发送缓冲为空中断[第1位]
    //以下是中断设置 设置为中断通道0
    VICIntSelect = 0x00000000;
    VICVectCntl0 = 0x26; //第5位置1:向量使能,[4:0]中断源序号
    VICVectAddr0 = (unsigned long)&IRQ_UART_0;
    //jtk 当发生向量中断时处理器自动把 VICVectAddrN 赋给 VICVectAddr
    VICIntEnable = 0x00000040;   
    PINSEL0 |= 0x00000005;
}

1.1.3 中断处理函数
__irq __arm void IRQ_UART_0(void)
{
    …………
    VICVectAddr = 0x00;
}


1.2 第二方法,先跳转到一个处理函数然后再跳转到对应的中断处理函数

1.2.1 启动代码

        ARM
__vector:  
        ;jtk 绝对跳转,跳转到相应的异常处理程序,PC总是指向当前指令的下两条指令的地址,即PC的值为当前指令的地址值加8个字节
        ;jtk 所以LDR PC, [PC,#24]跳转到24+8=32字节后
        ldr   pc,[pc,#+24]              ;; Reset jtk 跳转到__iar_program_start
        ldr   pc,[pc,#+24]              ;; Undefined instructions
        B   .                           ;; Software interrupt (SWI/SVC)
        ldr   pc,[pc,#+24]              ;; Prefetch abort
        ldr   pc,[pc,#+24]              ;; Data abort
__vector_0x14
        DC32  0                         ;; RESERVED
        ldr   pc,[pc,#+24]              ;; IRQ
        ldr   pc,[pc,#+24]              ;; FIQ
;jtk 上面的中断向量跳转到这里来,如果在c语言中有定义,
;下面的标号如果在c语言中有相应的处理程序,那么一旦有中断产生就会跳到相应的中断函数去
        DC32  __iar_program_start       ;; Reset
        DC32  undef_handler             ;; Undefined instructions
        DC32  0                         ;; Software interrupt (SWI/SVC)
        DC32  prefetch_handler          ;; Prefetch abort
        DC32  data_handler              ;; Data abort
        DC32  0                         ;; RESERVED
        DC32  irq_handler               ;; IRQ  跳转到 irq_handler 这个函数
        DC32  fiq_handler               ;; FIQ

        
void Init_key()
{
    PINSEL1_bit.P0_16 = 1;//引脚P0.16选择为外部中断功能

    EXTWAKE=0X00;//jtk 不作为唤醒用,为1时处理器从掉电模式唤醒
    EXTMODE =0x00;//jtk 为0用电平激活,为1时是边缘激活
    EXTPOLAR=0x00;//jtk 为低电平或下降沿有效

    VICIntSelect_bit.EINT0 =0;  //jtk 中断选择寄存器第14位是0就行。
    //第5位置1:向量使能,[4:0]中断源序号
    VICVectCntl9 = 0x20|14;//将9号IRQ slot设置为向量中断(第5位为1使能向量中断,为0时是非向量中断)
    VICVectAddr9 = (unsigned int)KEY_IRQ; //当设置为向量中断时,中断函数地址给 VICVectAddrN  
    VICDefVectAddr = (unsigned long)KEY_IRQ; //当设置为非向量中断时,中断函数地址给 VICDefVectAddr
    //当一个IRQ服务程序读取向量地址寄存器 VICVectAddr ,并且没有 IRQ slot 响应时,则返回 VICDefVectAddr 的地址
    //所以当没有 IRQ slot 响应时,则 VICDefVectAddr 的地址被读取了,这样就变成了处理非向量中断的程序了
    //KEY_IRQ; //中断函数地址

    EXTINT=0X01;//jtk 通过向 EXTINT 寄存器 写入 1 来将其清零
    VICIntEnable_bit.EINT0 = 1;//中断使能寄存器 查表可知ext0的中断源号是14,第14位置1.
}

 __irq __arm void irq_handler (void)        //公共中断处理函数,检查 VICVectAddr 是否为空
{
    void (*interrupt_function)();
    unsigned int vector;

    vector = VICVectAddr;     // Get interrupt vector.
//jtk 如果作为向量中断,这里把 VICVectAddrN 赋给 vector 和把 VICVectAddr 赋给 vector 都可以,
//jtk 当发生向量中断时处理器自动把 VICVectAddrN 赋给 VICVectAddr
    interrupt_function = (void(*)())vector;
    if(interrupt_function !=NULL){
       interrupt_function();  // Call vectored interrupt function.
    }else{
        VICVectAddr = 0;      // Clear interrupt in VIC.
    }
}


二、非向量中断

        ARM
__vector:  
        ;jtk 绝对跳转,跳转到相应的异常处理程序,PC总是指向当前指令的下两条指令的地址,即PC的值为当前指令的地址值加8个字节
        ;jtk 所以LDR PC, [PC,#24]跳转到24+8=32字节后
        ldr   pc,[pc,#+24]              ;; Reset jtk 跳转到__iar_program_start
        ldr   pc,[pc,#+24]              ;; Undefined instructions
        B   .                           ;; Software interrupt (SWI/SVC)
        ldr   pc,[pc,#+24]              ;; Prefetch abort
        ldr   pc,[pc,#+24]              ;; Data abort
__vector_0x14
        DC32  0                         ;; RESERVED
        ldr   pc,[pc,#+24]              ;; IRQ
        ldr   pc,[pc,#+24]              ;; FIQ
;jtk 上面的中断向量跳转到这里来,如果在c语言中有定义,
;下面的标号如果在c语言中有相应的处理程序,那么一旦有中断产生就会跳到相应的中断函数去
        DC32  __iar_program_start       ;; Reset
        DC32  undef_handler             ;; Undefined instructions
        DC32  0                         ;; Software interrupt (SWI/SVC)
        DC32  prefetch_handler          ;; Prefetch abort
        DC32  data_handler              ;; Data abort
        DC32  0                         ;; RESERVED
        DC32  irq_handler               ;; IRQ  跳转到 irq_handler 这个函数
        DC32  fiq_handler               ;; FIQ

 2.1.2 初始化
void Init_key()
{
    PINSEL1_bit.P0_16 = 1;//引脚P0.16选择为外部中断功能

    EXTWAKE=0X00;//jtk 不作为唤醒用,为1时处理器从掉电模式唤醒
    EXTMODE =0x00;//jtk 为0用电平激活,为1时是边缘激活
    EXTPOLAR=0x00;//jtk 为低电平或下降沿有效

    VICIntSelect_bit.EINT0 =0;  //jtk 中断选择寄存器第14位是0就行。
    //第5位置1:向量使能,[4:0]中断源序号
    VICDefVectAddr = (unsigned long)KEY_IRQ; //当设置为非向量中断时,中断函数地址给 VICDefVectAddr
    //当一个IRQ服务程序读取向量地址寄存器 VICVectAddr ,并且没有 IRQ slot 响应时,则返回 VICDefVectAddr 的地址
    //所以当没有 IRQ slot 响应时,则 VICDefVectAddr 的地址被读取了,这样就变成了处理非向量中断的程序了
    //KEY_IRQ; //中断函数地址

    EXTINT=0X01;//jtk 通过向 EXTINT 寄存器 写入 1 来将其清零
    VICIntEnable_bit.EINT0 = 1;//中断使能寄存器 查表可知ext0的中断源号是14,第14位置1.
}

2.1.3 公共中断处理函数
 __irq __arm void irq_handler (void)        //公共中断处理函数,检查 VICVectAddr 是否为空
{
    void (*interrupt_function)();
    unsigned int vector;

/*********jtk 当只有一个中断源时可以这样处理*************************/
    vector = VICVectAddr;     // Get interrupt vector.
//jtk 如果作为非向量中断,这里把 VICDefVectAddr 赋给 vector 和把 VICVectAddr 赋给 vector 都可以,
//jtk 因为当发生非向量中断时处理器自动把 VICDefVectAddr 赋给 VICVectAddr
    interrupt_function = (void(*)())vector;
    if(interrupt_function !=NULL){
       interrupt_function();  // Call vectored interrupt function.
    }else{
        VICVectAddr = 0;      // Clear interrupt in VIC.
    }

/*********jtk 当只有一个中断源时可以这样处理*************************/


//jtk 当有多个中断时可以通过读 VICIRQStatus 寄存器来判断是哪个中断产生了,并跳转到相应的处理函数
}

2.1.4 中断处理函数

void KEY_IRQ(void)
{  
  EXTINT=0X01;//jtk 通过向 EXTINT 寄存器 写入 1 来将其清零
  …………
 VICVectAddr = 0;     //中断程序结束时对向量地址寄存器执行 写 “0”操作
}

三、 FIQ 中断

可以通过设置 VICIntSelect 把对应的中断设置为 FIQ
当设置了多个 FIQ 中断时 可以通过读 VICFIQStatus 寄存器来判断具体是哪个中断,处理方法跟非向量中断差不多


四、如果中断中既有向量中断又有非向量中断,那么向量中断的处理函数放在对应的 VICVectAddrN 中,而非向量中断都放在  VICDefVectAddr,然后可以在  VICDefVectAddr 对应的函数上进行区分不同的非向量中断。

你可能感兴趣的:(arm7 LPC2103 中断的处理方法)