我們按照Tiny210官方的裸板程式來梳理S5PV210的中斷體系。 關於 S5PV210 的中斷體繫結構 S5PV210 的中斷控制器是由 4 個向量中斷控制器(VIC)、 ARM PrimeCell PL192 和 4 個 TrustZone Interrupt Controller (TZIC ...
我們按照Tiny210官方的裸板程式來梳理S5PV210的中斷體系。
關於 S5PV210 的中斷體繫結構
S5PV210 的中斷控制器是由 4 個向量中斷控制器(VIC)、 ARM PrimeCell PL192 和 4 個
TrustZone Interrupt Controller (TZIC)共同組成。
S5PV210 共支持 93 個中斷源(具體見官方手冊)。
首先看 Start.S
.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}^
設置 CPSR = #0x53,進入SVC模式,開IRQ中斷。
接著在main函數中會調用 system_initexception 函數:
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
VIC0ADDR = 0;
VIC1ADDR = 0;
VIC2ADDR = 0;
VIC3ADDR = 0;
}
然後設置 VICINTENABLE 使能中斷。
我們只關心這條就可以:
pExceptionIRQ = (unsigned long)IRQ_handle;
頭文件中這樣定義:
#define _Exception_Vector 0xD0037400
#define pExceptionIRQ ( *((volatile unsigned long *)(_Exception_Vector + 0x18)) )
而S5PV210 的異常向量表的起始地址是0xD0037400,原因見下圖:
這樣,在發生IRQ中斷時,PC就會跳轉到 pExceptionIRQ 地址處,從而執行了 IRQ_handle 函數,接著又執行了 irq_handler 函數。
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)();
}
通過調用 intc_getvicirqstatus 函數返回 VICIRQSTATUS 的值就知道當前VIC中是否有中斷請求,有的話就會將isr賦值為 VICADDR 的值,即(服務函數的地址),然後調用服務程式。
有一點需要說明:
當有中斷發生時,硬體上會將當前中斷的中斷處理函數從寄存器 VICVECTADDR 自動拷貝到寄存器
VICADDR 中, 所以我們在 irq_handler()函數里會調用保存在寄存器 VICADDR 里的中斷處理函數。假如我們要開啟 EXINT0 中斷,那麼我們只需將中斷服務程式的地址賦值給 VIC0VECTADDR0 即可。