S5PV210中断体系结构分析

我们按照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中断。
S5PV210中断体系结构分析_第1张图片

接着在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,原因见下图:

S5PV210中断体系结构分析_第2张图片

这样,在发生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 即可。

转载于:https://www.cnblogs.com/GyForever1004/p/8367272.html

你可能感兴趣的:(S5PV210中断体系结构分析)