1. OVERVIEW OF VECTORED INTERRUPT CONTROLLER(概述向量中斷控制器)php
主要有4個VIC,4個TZIC還有一個很特殊的ARM PrimeCell PL192。主要的VIC和TZIC能夠支持93箇中斷源。其中TZIC是爲TrustZone技術所準備的,ARM TrustZone® 技術是系統範圍的安全方法,針對高性能計算平臺上的大量應用,包括安全支付、數字版權管理 (DRM)、企業服務和基於 Web 的服務(援引官方的介紹)。TZIC提供了安全控制的nFIQ中斷而且使該這類中斷從傳統的不安全中斷VIC中屏蔽掉,從而達到應用在數據傳輸時的安全性和保密性。c++
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用戶手冊。性能
中斷參考程序:spa
.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 裏的中斷處理函數便可。 rest
( 一箇中斷組有32箇中斷源,爲何咱們能夠直接運行中斷組的VICxINTADDR指定的函數而無需知道是具體哪一個中斷源觸發了中斷呢?這是因爲中斷組內的中斷源在觸發中斷後硬件會自動把對應中斷源的處理函數入口地址賦給所屬組的VICADDR,這樣咱們就能省去檢索中斷源再跳轉到對應中斷函數入口的時間了,固然,前提是咱們要把【按鍵中斷】的服務程序入口地址賦給某個對應的寄存器(假設是VIC0INTADDR12,所屬組是VIC0組,所對應入口是VIC0INTADDR))。 blog
這一段真的有點難懂,須要花點時間ci
#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\r\n"); // 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 *************** \r\n"); // 外部中斷相關的設置 // 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\r\n",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.\n"); while(1); } void exceptionswi(void) { printf("swi exception.\n"); while(1); } void exceptionpabort(void) { printf("pabort exception.\n"); while(1); } void exceptiondabort(void) { printf("dabort exception.\n"); 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)(); }