中断方式1:发生中断后,在中断处理函数内读中断状态寄存器得到中断源(是uart还是key还是其他),再经过switch(中断源)各个case调用到不同的处理函数

中断方式2:发生中断后,芯片自己判断中断源并跳转到我们预先给“中断源处理地址寄存器”设定的地址处运行。(S5PV210)

VIC:vector interrupt controller: 使用4个VIC来处理一共93个中断源 VIC[0-3]

  1. 向量中断控制器中硬件实现的向量表
    1
    2
    3
    4
    5
    VIC0VECTORADDR0
    ...
    VIC0VECTORADDR16 //key接到了16号中断,所以关心这个寄存器
    ...
    VIC0VECTORADDR31
  2. 中断源的优先级寄存器
    1
    2
    3
    4
    5
    VIC0VECPRIORITY0
    ...
    VIC0VECPRIORITY16 //暂时不关心优先级
    ...
    VIC0VECPRIORITY31
  3. 对控制器做开关
    1
    2
    VIC0INTENABLE
    VIC0INTENCLEAR
  4. 状态寄存器
    1
    2
    VIC0IRQSTATUS
    VIC0FIQSTATUS
  5. 中断处理函数地址寄存器
    1
    VIC0ADDRESS
    多个中断源(gpio,extern,uart,key…)控制器 –> VIC[0-4] -> 中断主控制器 –> CPU
1
2
asm_irq:
b irq_handler
1
2
3
4
5
6
7
8
9
10
extern void asm_irq(void);
void irq_init(void){
#if 0 //方案1:直接把指令内容放到寄存器,中断来之后cpu直接执行该指令(无法工作)
unsigned int tmp;
tmp = *((unsigned int *)asm_irq); //把asm_irq地址的4字节内容赋值给tmp(也就是把指令赋值给tmp)
pEXECEPTION_IRQ = tmp; //把指令赋值给该寄存器,当发生中断,该寄存器内的指令被cpu执行
#else //方案2:把地址放到寄存器,中断来之后cpu读出该地址的指令来执行
pEXECEPTION_IRQ = (unsigned int)asm_irq;
#endif
}
1
2
3
4
5
irq_handler:
stmfd sp!,{r0-r3,lr}
bl irq_c_handler
ldmfd sp!,{r0-r3,lr}
subs pc,lr,#4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
void irq_c_handler(void){
myputs("irq_c_handler\n");
if(VIC0IRQSTATU|VIC1IRQSTATUS|VIC2IRQSTATUS|SVIC3IRQSTATUS){ }
void (*handler)(void) = NULL;
handler = (void (*)(void))VIC0ADDRESS; //handler的值应该就是key1_handler
if(handler) handler();
}
void key1_handler(void){
myputs("key1_handler\n");
set EXT_INT_2_PENDING[0] = 1; //清除中断源控制器的pending位EXT_INT[16]。pending:用于多个中断源同时发生,pending寄存器就暂存中断信号,等cpu处理完一个之后将其取消,接着处理下一个中断源
set VIC0ADDRESS = 0; //清除中断主控制器的pending
}

void key_init(void)
{
//1.对引脚进行功能选择,把GPH2.0引脚配置为中断 EXT_INT[16]
set GPH2.CON[3:0] = 1111;

//配置中断源(extern)控制器 extern interrupt controller register
set EXT_INT_2_CON[2:0] = 0b010; //上升沿触发EXT_INT[16]
set EXT_INT_2_MASK[0] = 0b0; //取消屏蔽EXT_INT[16],让中断可以去到主中断控制器

//配置中断主控制器
set VIC0INTENABLE[16] = 1; //使能接受中断EXT_INT[16],若想禁用 set VIC0INTENCLEAR[16] = 1;
VIC0VECTORADDR16 = key1_handler; //把处理函数的地址放到寄存器里面,当发生中断时,该地址会被cpu写到VIC0ADDRESS里面
}

int main(void)
{
irq_init();
key_init();
while(1);
return 0;
}