1、中断的生命周期
中断信号产生(中断源)—》中断信号过滤(中断控制器)—》中断信号处理(CPU)
1.1 中断源
在中断的生命周期中,中断源的作用是负责产生中断信号。
S3C2440支持60个中断源(包含子中断源,不包括EINT8_23等里面的独立中断源,例如串口的发送中断、接收中断、错误中断属于串口的子中断源。);
S3C6410支持64个中断源;
S5PV210支持93个中断源;
1.2 中断控制器
1.3 中断处理
1)非向量方式(2440)
2)向量方式(6410/210)
(对于向量方式,是直接进入中断函数(而不是跳转到中断程序总入口),因为中断函数(的地址)保存在相应寄存器里,根据相应中断源跳转到对应的中断函数处)
1.4 总结
中断代码的编辑过程:
初始化中断源–>初始化中断控制器–>中断处理代码
2 、按键中断点亮LED
先将之前写的代码进行优化(将各个部分的代码移植到相应新建的.c文件中)
(主要是touch ~~.c chmod 777 ~~.c)
1)中断源的初始化
将四个按键对应的引脚设为外部中断模式
#define GPGCON (volatile unsigned long *)0x56000060 /* K1,K2,K3,K4对应GPG0、GPG3、GPG5、GPG6*/ #define GPG5_int(0x2<2)初始化中断控制器
在初始化程序中,首先将外部中断8、11、13、14使能。
因为外部中断8、11、13、14属于中断源EINT8_23,将其使能。
操作状态寄存器cpsr的第7位,打开IRQ中断
3)中断处理
因为外部中断源为EINT8_23,所以直接使用寄存器INTOFFSET(判断中断请求源寄存器)是不行的,需要使用寄存器EINTPEND(外部中断未决寄存器)(当这个寄存器的对应位为1时,表示产生了相应中断,在产生完中断后,需要将该位写1来清除中断)。
中断控制器初始化和中断处理的源代码如下:
/*interrupt registes*/
#define SRCPND(volatile unsigned long *)0x4A000000
#define INTMOD(volatile unsigned long *)0x4A000004
#define INTMSK(volatile unsigned long *)0x4A000008
#define PRIORITY(volatile unsigned long *)0x4A00000c
#define INTPND(volatile unsigned long *)0x4A000010
#define INTOFFSET(volatile unsigned long *)0x4A000014
#define SUBSRCPND(volatile unsigned long *)0x4A000018
#define INTSUBMSK(volatile unsigned long *)0x4A00001c
#define EINTMASK (volatile unsigned long *)0x560000a4
{// 在EINTMASK寄存器中使能它们
*(EINTMASK) &= (~(1<<8)) & (~(1<<11)) & (~(1<<13)) & (~(1<<14));// EINT8_23使能
*(INTMSK) &= ~(1<<5);
__asm__(
/*开中断*/
"mrs r0,cpsrn"
"bic r0, r0, #0x80n"
"msr cpsr_c, r0n"
);
}void handle_int()
{ /*读取产生中断的源*/
unsigned long value = *(EINTPEND) & ((1<<8)|(1<<11)|(1<<13)|(1<<14));
switch(value)
{ case (1<<8): //K1
led_on();break;case (1<<11): //K2
led_off();break; case (1<<13): //K3
led_on();break;case (1<<14): //K4
led_off(); break;
default:break;
} /* 中断清除 */
*(EINTPEND) = value; //SRCPND:记录当前有哪些中断发生?依据是否有多个中断同时发生,可能会有多个置位
//INTPND:记录经过INTMSK,优先仲裁后,哪个中断会被当前处理
//通过对中断未决寄存器SRCPND和INTPND相应位写1 来清除未决条件
*(SRCPND) = 1 << 5; //Indicate the interrupt request status.
*(INTPND) = 1 << 5;start.S中,当程序发生中断时,就会跳到中断处执行
[object Object]
(对于main.c只需要调用相应的函数就行了,为了验证中断的效果,使用宏定义的方式将MMU关闭,则将控制led的IO口的地址设为实际地址。)
在完成了以上的工作后,发现LED还是不能 点亮,其原因是因为在start.S文件中,程序首先进入的是SVC模式,在对栈的设置时,实际上是SVC模式下对栈指针SP(R13_svc)的设置,而中断中cpu进入的是IRQ模式,需要在此模式下对栈进行初始化。代码如下:
init_stack: msr cpsr_c, #0xd2 //进入中断模式 ldr sp, =0x33000000 //初始化r13_irq msr cpsr_c, #0xd3 //进入svc模式 ldr sp, =0x34000000 //初始化R13_svc mov pc ,lr附main.c代码:
int gboot_main() {#ifdef MMU_ON mmu_init();#endif led_init(); button_init(); init_irq(); while(1); return 0; }