1. OVERVIEW OF VECTORED INTERRUPT CONTROLLER(概述向量中断控制器)
主要有4个VIC,4个TZIC还有一个很特殊的ARM PrimeCell PL192。主要的VIC和TZIC可以支持93个中断源。其中TZIC是为TrustZone技术所准备的,ARM TrustZone® 技术是系统范围的安全方法,针对高性能计算平台上的大量应用,包括安全支付、数字版权管理 (DRM)、企业服务和基于 Web 的服务(援引官方的介绍)。TZIC提供了安全控制的nFIQ中断并且使该这类中断从传统的不安全中断VIC中屏蔽掉,从而达到应用在数据传输时的安全性和保密性。
2,KEY FEATURES OF VECTORED INTERRUPT CONTROLLER
• Supports 93 vectored IRQ interrupts
• Fixed hardware interrupts priority levels (固定硬件中断优先级)
• Programmable interrupt priority levels (可编程中断优先级)
• Supports Hardware interrupt priority level masking (支持硬件中断优先级的屏蔽)
• Programmable interrupt priority level masking
• Generates IRQ and FIQ (产生IRQ和FIQ)
• Generates Software interrupt
• Test registers
• Raw interrupt status (原中断状态,就是设置使能,屏蔽寄存器之前的各中断状态)
• Interrupt request status
• Supports Privileged mode for restricted access(支持限制访问特权模式)
3. When user clears interrupt pending, user must write 0 to all the VICADDRESS registers (VIC0ADDRESS,
VIC1ADDRESS, VIC2ADDRESS, and VIC3ADDRESS).
4.各中断寄存器请参考s5pv320用户手册。
中断参考程序:
.global _start .global IRQ_handle _start: // 关闭看门狗 ldr r0, =0xE2700000 mov r1, #0 str r1, [r0] // 设置栈,以便调用c函数 ldr sp, =0x40000000 // 开中断 mov r0, #0x53 msr CPSR_cxsf, r0 // 汇编初始化时钟 bl clock_init // 调用main函数 bl main IRQ_handle: // 设置中断模式的栈 ldr sp, =0xD0037F80 // 保存现场 sub lr, lr, #4 stmfd sp!, {r0-r12, lr} // 跳转到中断处理函数 bl irq_handler // 恢复现场 ldmfd sp!, {r0-r12, pc}^
首先,关闭看门狗,设置栈,开中断,设置时钟,,,当一个中断源(不是一个中断)发生时执行中断服务程序IRQ_handle,设置中断模式的栈, 保存现场,跳转到中断处理函(irq_handler),中断处理函数首先判断是哪个中断组发生中断,然后进入相应的中断处理子程序(irq_xxx),在事先我们要设置中断处理子程序irq_xxx(如irq_key)在地址VICxVECTADDRx中,,,当有中断发生时,硬件上会将当前中断的中断处理子程序从寄存器 VICxVECTADDxR 自动拷贝到寄存器VICADDR 中,所以我们在 irq_handler()函数里会调用保存在寄存器 VICDDR 里的中断处理函数即可。
( 一个中断组有32个中断源,为什么我们可以直接运行中断组的VICxINTADDR指定的函数而无需知道是具体哪个中断源触发了中断呢?这是由于中断组内的中断源在触发中断后硬件会自动把对应中断源的处理函数入口地址赋给所属组的VICADDR,这样我们就能省去检索中断源再跳转到对应中断函数入口的时间了,当然,前提是我们要把【按键中断】的服务程序入口地址赋给某个对应的寄存器(假设是VIC0INTADDR12,所属组是VIC0组,所对应入口是VIC0INTADDR))。
这一段真的有点难懂,需要花点时间
#include "stdio.h" #include "int.h" #define GPH2CON (*(volatile unsigned long *) 0xE0200C40) #define GPH2DAT (*(volatile unsigned long *) 0xE0200C44) #define GPH2_0_EINT16 (0xf<<(0*4)) #define GPH2_1_EINT17 (0xf<<(1*4)) #define GPH2_2_EINT18 (0xf<<(2*4)) #define GPH2_3_EINT19 (0xf<<(3*4)) #define EXT_INT_0_CON ( *((volatile unsigned long *)0xE0200E00) ) #define EXT_INT_1_CON ( *((volatile unsigned long *)0xE0200E04) ) #define EXT_INT_2_CON ( *((volatile unsigned long *)0xE0200E08) ) #define EXT_INT_3_CON ( *((volatile unsigned long *)0xE0200E0C) ) #define EXT_INT_0_MASK ( *((volatile unsigned long *)0xE0200F00) ) #define EXT_INT_1_MASK ( *((volatile unsigned long *)0xE0200F04) ) #define EXT_INT_2_MASK ( *((volatile unsigned long *)0xE0200F08) ) #define EXT_INT_3_MASK ( *((volatile unsigned long *)0xE0200F0C) ) #define EXT_INT_0_PEND ( *((volatile unsigned long *)0xE0200F40) ) #define EXT_INT_1_PEND ( *((volatile unsigned long *)0xE0200F44) ) #define EXT_INT_2_PEND ( *((volatile unsigned long *)0xE0200F48) ) #define EXT_INT_3_PEND ( *((volatile unsigned long *)0xE0200F4C) ) void uart_init(); // 延时函数 void delay(unsigned long count) { volatile unsigned long i = count; while (i--); } void isr_key(void) { printf("we get company:EINT16_31 "); // clear VIC0ADDR intc_clearvectaddr(); // clear pending bit EXT_INT_2_PEND |= 1<<0; } int main(void) { int c = 0; // 初始化串口 uart_init(); // 中断相关初始化 system_initexception(); printf("**************Int test *************** "); // 外部中断相关的设置 // 1111 = EXT_INT[16] GPH2CON |= 0xF; // 010 = Falling edge triggered EXT_INT_2_CON |= 1<<1; // unmasked EXT_INT_2_MASK &= ~(1<<0); // 设置中断EINT16_31的处理函数 intc_setvectaddr(NUM_EINT16_31, isr_key); // 使能中断EINT16_31 intc_enable(NUM_EINT16_31); while (1) { printf("%d ",c++); delay(0x100000); } }
#include "int.h" #include "stdio.h" //// Interrupt #define VIC0_BASE (0xF2000000) #define VIC1_BASE (0xF2100000) #define VIC2_BASE (0xF2200000) #define VIC3_BASE (0xF2300000) // VIC0 #define VIC0IRQSTATUS ( *((volatile unsigned long *)(VIC0_BASE + 0x00)) ) #define VIC0FIQSTATUS ( *((volatile unsigned long *)(VIC0_BASE + 0x04)) ) #define VIC0RAWINTR ( *((volatile unsigned long *)(VIC0_BASE + 0x08)) ) #define VIC0INTSELECT ( *((volatile unsigned long *)(VIC0_BASE + 0x0c)) ) #define VIC0INTENABLE ( *((volatile unsigned long *)(VIC0_BASE + 0x10)) ) #define VIC0INTENCLEAR ( *((volatile unsigned long *)(VIC0_BASE + 0x14)) ) #define VIC0SOFTINT ( *((volatile unsigned long *)(VIC0_BASE + 0x18)) ) #define VIC0SOFTINTCLEAR ( *((volatile unsigned long *)(VIC0_BASE + 0x1c)) ) #define VIC0PROTECTION ( *((volatile unsigned long *)(VIC0_BASE + 0x20)) ) #define VIC0SWPRIORITYMASK ( *((volatile unsigned long *)(VIC0_BASE + 0x24)) ) #define VIC0PRIORITYDAISY ( *((volatile unsigned long *)(VIC0_BASE + 0x28)) ) #define VIC0VECTADDR (VIC0_BASE + 0x100) #define VIC0VECPRIORITY ( *((volatile unsigned long *)(VIC0_BASE + 0x200)) ) #define VIC0ADDR ( *((volatile unsigned long *)(VIC0_BASE + 0xf00)) ) #define VIC0PERID0 ( *((volatile unsigned long *)(VIC0_BASE + 0xfe0)) ) #define VIC0PERID1 ( *((volatile unsigned long *)(VIC0_BASE + 0xfe4)) ) #define VIC0PERID2 ( *((volatile unsigned long *)(VIC0_BASE + 0xfe8)) ) #define VIC0PERID3 ( *((volatile unsigned long *)(VIC0_BASE + 0xfec)) ) #define VIC0PCELLID0 ( *((volatile unsigned long *)(VIC0_BASE + 0xff0)) ) #define VIC0PCELLID1 ( *((volatile unsigned long *)(VIC0_BASE + 0xff4)) ) #define VIC0PCELLID2 ( *((volatile unsigned long *)(VIC0_BASE + 0xff8)) ) #define VIC0PCELLID3 ( *((volatile unsigned long *)(VIC0_BASE + 0xffc)) ) // VIC1 #define VIC1IRQSTATUS ( *((volatile unsigned long *)(VIC1_BASE + 0x00)) ) #define VIC1FIQSTATUS ( *((volatile unsigned long *)(VIC1_BASE + 0x04)) ) #define VIC1RAWINTR ( *((volatile unsigned long *)(VIC1_BASE + 0x08)) ) #define VIC1INTSELECT ( *((volatile unsigned long *)(VIC1_BASE + 0x0c)) ) #define VIC1INTENABLE ( *((volatile unsigned long *)(VIC1_BASE + 0x10)) ) #define VIC1INTENCLEAR ( *((volatile unsigned long *)(VIC1_BASE + 0x14)) ) #define VIC1SOFTINT ( *((volatile unsigned long *)(VIC1_BASE + 0x18)) ) #define VIC1SOFTINTCLEAR ( *((volatile unsigned long *)(VIC1_BASE + 0x1c)) ) #define VIC1PROTECTION ( *((volatile unsigned long *)(VIC1_BASE + 0x20)) ) #define VIC1SWPRIORITYMASK ( *((volatile unsigned long *)(VIC1_BASE + 0x24)) ) #define VIC1PRIORITYDAISY ( *((volatile unsigned long *)(VIC1_BASE + 0x28)) ) #define VIC1VECTADDR (VIC1_BASE + 0x100) #define VIC1VECPRIORITY ( *((volatile unsigned long *)(VIC1_BASE + 0x200)) ) #define VIC1ADDR ( *((volatile unsigned long *)(VIC1_BASE + 0xf00)) ) #define VIC1PERID0 ( *((volatile unsigned long *)(VIC1_BASE + 0xfe0)) ) #define VIC1PERID1 ( *((volatile unsigned long *)(VIC1_BASE + 0xfe4)) ) #define VIC1PERID2 ( *((volatile unsigned long *)(VIC1_BASE + 0xfe8)) ) #define VIC1PERID3 ( *((volatile unsigned long *)(VIC1_BASE + 0xfec)) ) #define VIC1PCELLID0 ( *((volatile unsigned long *)(VIC1_BASE + 0xff0)) ) #define VIC1PCELLID1 ( *((volatile unsigned long *)(VIC1_BASE + 0xff4)) ) #define VIC1PCELLID2 ( *((volatile unsigned long *)(VIC1_BASE + 0xff8)) ) #define VIC1PCELLID3 ( *((volatile unsigned long *)(VIC1_BASE + 0xffc)) ) // VIC2 #define VIC2IRQSTATUS ( *((volatile unsigned long *)(VIC2_BASE + 0x00)) ) #define VIC2FIQSTATUS ( *((volatile unsigned long *)(VIC2_BASE + 0x04)) ) #define VIC2RAWINTR ( *((volatile unsigned long *)(VIC2_BASE + 0x08)) ) #define VIC2INTSELECT ( *((volatile unsigned long *)(VIC2_BASE + 0x0c)) ) #define VIC2INTENABLE ( *((volatile unsigned long *)(VIC2_BASE + 0x10)) ) #define VIC2INTENCLEAR ( *((volatile unsigned long *)(VIC2_BASE + 0x14)) ) #define VIC2SOFTINT ( *((volatile unsigned long *)(VIC2_BASE + 0x18)) ) #define VIC2SOFTINTCLEAR ( *((volatile unsigned long *)(VIC2_BASE + 0x1c)) ) #define VIC2PROTECTION ( *((volatile unsigned long *)(VIC2_BASE + 0x20)) ) #define VIC2SWPRIORITYMASK ( *((volatile unsigned long *)(VIC2_BASE + 0x24)) ) #define VIC2PRIORITYDAISY ( *((volatile unsigned long *)(VIC2_BASE + 0x28)) ) #define VIC2VECTADDR (VIC2_BASE + 0x100) #define VIC2VECPRIORITY ( *((volatile unsigned long *)(VIC2_BASE + 0x200)) ) #define VIC2ADDR ( *((volatile unsigned long *)(VIC2_BASE + 0xf00)) ) #define VIC2PERID0 ( *((volatile unsigned long *)(VIC2_BASE + 0xfe0)) ) #define VIC2PERID1 ( *((volatile unsigned long *)(VIC2_BASE + 0xfe4)) ) #define VIC2PERID2 ( *((volatile unsigned long *)(VIC2_BASE + 0xfe8)) ) #define VIC2PERID3 ( *((volatile unsigned long *)(VIC2_BASE + 0xfec)) ) #define VIC2PCELLID0 ( *((volatile unsigned long *)(VIC2_BASE + 0xff0)) ) #define VIC2PCELLID1 ( *((volatile unsigned long *)(VIC2_BASE + 0xff4)) ) #define VIC2PCELLID2 ( *((volatile unsigned long *)(VIC2_BASE + 0xff8)) ) #define VIC2PCELLID3 ( *((volatile unsigned long *)(VIC2_BASE + 0xffc)) ) // VIC3 #define VIC3IRQSTATUS ( *((volatile unsigned long *)(VIC3_BASE + 0x00)) ) #define VIC3FIQSTATUS ( *((volatile unsigned long *)(VIC3_BASE + 0x04)) ) #define VIC3RAWINTR ( *((volatile unsigned long *)(VIC3_BASE + 0x08)) ) #define VIC3INTSELECT ( *((volatile unsigned long *)(VIC3_BASE + 0x0c)) ) #define VIC3INTENABLE ( *((volatile unsigned long *)(VIC3_BASE + 0x10)) ) #define VIC3INTENCLEAR ( *((volatile unsigned long *)(VIC3_BASE + 0x14)) ) #define VIC3SOFTINT ( *((volatile unsigned long *)(VIC3_BASE + 0x18)) ) #define VIC3SOFTINTCLEAR ( *((volatile unsigned long *)(VIC3_BASE + 0x1c)) ) #define VIC3PROTECTION ( *((volatile unsigned long *)(VIC3_BASE + 0x20)) ) #define VIC3SWPRIORITYMASK ( *((volatile unsigned long *)(VIC3_BASE + 0x24)) ) #define VIC3PRIORITYDAISY ( *((volatile unsigned long *)(VIC3_BASE + 0x28)) ) #define VIC3VECTADDR (VIC3_BASE + 0x100) #define VIC3VECPRIORITY ( *((volatile unsigned long *)(VIC3_BASE + 0x200)) ) #define VIC3ADDR ( *((volatile unsigned long *)(VIC3_BASE + 0xf00)) ) #define VIC3PERID0 ( *((volatile unsigned long *)(VIC3_BASE + 0xfe0)) ) #define VIC3PERID1 ( *((volatile unsigned long *)(VIC3_BASE + 0xfe4)) ) #define VIC3PERID2 ( *((volatile unsigned long *)(VIC3_BASE + 0xfe8)) ) #define VIC3PERID3 ( *((volatile unsigned long *)(VIC3_BASE + 0xfec)) ) #define VIC3PCELLID0 ( *((volatile unsigned long *)(VIC3_BASE + 0xff0)) ) #define VIC3PCELLID1 ( *((volatile unsigned long *)(VIC3_BASE + 0xff4)) ) #define VIC3PCELLID2 ( *((volatile unsigned long *)(VIC3_BASE + 0xff8)) ) #define VIC3PCELLID3 ( *((volatile unsigned long *)(VIC3_BASE + 0xffc)) ) #define _Exception_Vector 0xD0037400 #define pExceptionRESET ( *((volatile unsigned long *)(_Exception_Vector + 0x0)) ) #define pExceptionUNDEF ( *((volatile unsigned long *)(_Exception_Vector + 0x4)) ) #define pExceptionSWI ( *((volatile unsigned long *)(_Exception_Vector + 0x8)) ) #define pExceptionPABORT ( *((volatile unsigned long *)(_Exception_Vector + 0xc)) ) #define pExceptionDABORT ( *((volatile unsigned long *)(_Exception_Vector + 0x10)) ) #define pExceptionRESERVED ( *((volatile unsigned long *)(_Exception_Vector + 0x14)) ) #define pExceptionIRQ ( *((volatile unsigned long *)(_Exception_Vector + 0x18)) ) #define pExceptionFIQ ( *((volatile unsigned long *)(_Exception_Vector + 0x1c)) ) void exceptionundef(void) { printf("undefined instruction exception. "); while(1); } void exceptionswi(void) { printf("swi exception. "); while(1); } void exceptionpabort(void) { printf("pabort exception. "); while(1); } void exceptiondabort(void) { printf("dabort exception. "); while(1); } // 中断相关初始化 void system_initexception( void) { // 设置中断向量表 pExceptionUNDEF = (unsigned long)exceptionundef; pExceptionSWI = (unsigned long)exceptionswi; pExceptionPABORT = (unsigned long)exceptionpabort; pExceptionDABORT = (unsigned long)exceptiondabort; pExceptionIRQ = (unsigned long)IRQ_handle; pExceptionFIQ = (unsigned long)IRQ_handle; // 初始化中断控制器 intc_init(); } // 初始化中断控制器 void intc_init(void) { // 禁止所有中断 VIC0INTENCLEAR = 0xffffffff; VIC1INTENCLEAR = 0xffffffff; VIC2INTENCLEAR = 0xffffffff; VIC3INTENCLEAR = 0xffffffff; // 选择中断类型为IRQ VIC0INTSELECT = 0x0; VIC1INTSELECT = 0x0; VIC2INTSELECT = 0x0; VIC3INTSELECT = 0x0; // 清VICxADDR intc_clearvectaddr(); } // 保存需要处理的中断的中断处理函数的地址 void intc_setvectaddr(unsigned long intnum, void (*handler)(void)) { //VIC0 if(intnum<32) { *( (volatile unsigned long *)(VIC0VECTADDR + 4*intnum) ) = (unsigned)handler; } //VIC1 else if(intnum<64) { *( (volatile unsigned long *)(VIC1VECTADDR + 4*(intnum-32)) ) = (unsigned)handler; } //VIC2 else if(intnum<96) { *( (volatile unsigned long *)(VIC2VECTADDR + 4*(intnum-64)) ) = (unsigned)handler; } //VIC3 else { *( (volatile unsigned long *)(VIC3VECTADDR + 4*(intnum-96)) ) = (unsigned)handler; } return; } // 清除需要处理的中断的中断处理函数的地址 void intc_clearvectaddr(void) { // VICxADDR:当前正在处理的中断的中断处理函数的地址 VIC0ADDR = 0; VIC1ADDR = 0; VIC2ADDR = 0; VIC3ADDR = 0; } // 使能中断 void intc_enable(unsigned long intnum) { unsigned long temp; if(intnum<32) { temp = VIC0INTENABLE; temp |= (1<<intnum); VIC0INTENABLE = temp; } else if(intnum<64) { temp = VIC1INTENABLE; temp |= (1<<(intnum-32)); VIC1INTENABLE = temp; } else if(intnum<96) { temp = VIC2INTENABLE; temp |= (1<<(intnum-64)); VIC2INTENABLE = temp; } else if(intnum<NUM_ALL) { temp = VIC3INTENABLE; temp |= (1<<(intnum-96)); VIC3INTENABLE = temp; } // NUM_ALL : enable all interrupt else { VIC0INTENABLE = 0xFFFFFFFF; VIC1INTENABLE = 0xFFFFFFFF; VIC2INTENABLE = 0xFFFFFFFF; VIC3INTENABLE = 0xFFFFFFFF; } } // 禁止中断 void intc_disable(unsigned long intnum) { unsigned long temp; if(intnum<32) { temp = VIC0INTENCLEAR; temp |= (1<<intnum); VIC0INTENCLEAR = temp; } else if(intnum<64) { temp = VIC1INTENCLEAR; temp |= (1<<(intnum-32)); VIC1INTENCLEAR = temp; } else if(intnum<96) { temp = VIC2INTENCLEAR; temp |= (1<<(intnum-64)); VIC2INTENCLEAR = temp; } else if(intnum<NUM_ALL) { temp = VIC3INTENCLEAR; temp |= (1<<(intnum-96)); VIC3INTENCLEAR = temp; } // NUM_ALL : disable all interrupt else { VIC0INTENCLEAR = 0xFFFFFFFF; VIC1INTENCLEAR = 0xFFFFFFFF; VIC2INTENCLEAR = 0xFFFFFFFF; VIC3INTENCLEAR = 0xFFFFFFFF; } return; } // 读中断状态 unsigned long intc_getvicirqstatus(unsigned long ucontroller) { if(ucontroller == 0) return VIC0IRQSTATUS; else if(ucontroller == 1) return VIC1IRQSTATUS; else if(ucontroller == 2) return VIC2IRQSTATUS; else if(ucontroller == 3) return VIC3IRQSTATUS; else {} return 0; } // 通用中断处理函数 void irq_handler(void) { unsigned long vicaddr[4] = {VIC0ADDR,VIC1ADDR,VIC2ADDR,VIC3ADDR}; int i=0; void (*isr)(void) = NULL; for(; i<4; i++) { if(intc_getvicirqstatus(i) != 0) { isr = (void (*)(void)) vicaddr[i]; break; } } (*isr)(); }