S5PV210有4个向量中断控制器(VIC),每个向量中断控制器包含32个中断源。
当某个中断源产生中断时,CPU会自动的将VICxVECTADDRy(x=0,1,2,3,y=0-31)寄存器的值赋给VICxADDRESS(x=0,1,2,3),因此我们可以把我们的中断处理函数的地址赋给VICxVECTADDRy寄存器,
比如我们有个函数
void key_handle()
{
……
}
我们把key_handle 函数的值赋给VIC0VECTADDR0(外部中断0)
VIC0VECTADDR0 =key_handle;
当外部中断0触发中断时,CPU会自动的将VIC0VECTADDR0的值赋给VIC0ADDRESS,并跳转到这个地址去执行,即执行函数key_handle。
代码如下:
start.S
.global _start /* 声明一个全局的标号 */ .global key_isr _start: /* 设置栈,以调用c函数 */ ldr sp, =0x40000000 /* 开总中断 */ mrs r0, cpsr bic r0, r0, #0x00000080 /* 清楚第7位,IRQ中断禁止位,写0使能IRQ */ msr cpsr, r0 bl main /* 跳转到C函数去执行 */ halt: b halt key_isr: /* 计算返回地址:PC的值等于当前执行的地址+8,当CPU正要执行某条指令时(还未执行),被中断, ** 这是这条刚要执行的指令的地址刚好=PC-4 */ sub lr, lr, #4 stmfd sp!, {r0-r12, lr} /* 保护现场 */ bl key_handle /* 恢复现场 */ ldmfd sp!, {r0-r12, pc}^ /* ^表示把spsr恢复到cpsr */
key.c
#define GPC0CON *((volatile unsigned int *)0xE0200060) #define GPC0DAT *((volatile unsigned int *)0xE0200064) #define GPH0CON *((volatile unsigned int *)0xE0200C00) #define GPH0DAT *((volatile unsigned int *)0xE0200C04) #define EXT_INT_0_CON *((volatile unsigned int *)0xE0200E00) #define EXT_INT_0_MASK *((volatile unsigned int *)0xE0200F00) #define VIC0INTSELECT *((volatile unsigned int *)0xF200000C) #define VIC0INTENABLE *((volatile unsigned int *)0xF2000010) #define VIC0VECTADDR0 *((volatile unsigned int *)0xF2000100) #define VIC0VECTADDR1 *((volatile unsigned int *)0xF2000104) #define VIC0ADDRESS *((volatile unsigned int *)0xF2000F00) #define EXT_INT_0_PEND *((volatile unsigned int *)0xE0200F40) extern void key_isr(void); void key_handle() { volatile unsigned char key_code = EXT_INT_0_PEND & 0x3; VIC0ADDRESS = 0; /* 清中断向量寄存器 */ EXT_INT_0_PEND |= 3; /* 清中断挂起寄存器 */ if (key_code == 1) /* key1 */ GPC0DAT ^= 1 << 3; /* toggle LED1 */ else if (key_code == 2) /* key2 */ GPC0DAT ^= 1 << 4; /* toggle LED2 */ } int main() { GPC0CON &= ~(0xFF << 12); GPC0CON |= 0x11 << 12; /* 配置GPC0_3和GPC0_4为输出:LED1和LED2 */ GPH0CON |= 0xFF << 0; /* 配置GPH0_0和GPH0_1为外部中断:key1和key2 */ EXT_INT_0_CON &= ~(0xFF << 0); EXT_INT_0_CON |= 2 | (2 << 4); /* 配置EXT_INT[0]和EXT_INT[1]为下降沿触发 */ EXT_INT_0_MASK &= ~3; /* 取消屏蔽外部中断EXT_INT[0]和EXT_INT[1] */ VIC0INTSELECT &= ~3; /* 选择外部中断EXT_INT[0]和外部中断EXT_INT[1]为IRQ类型的中断 */ VIC0INTENABLE |= 3; /* 使能外部中断EXT_INT[0]和EXT_INT[1] */ VIC0VECTADDR0 = (int)key_isr; /* 当EXT_INT[0]触发中断,即用户按下key1时, CPU就会自动的将VIC0VECTADDR0的值赋给VIC0ADDRESS并跳转到这个地址去执 */ VIC0VECTADDR1 = (int)key_isr; while (1); return 0; }
Makefile
key.bin: start.o key.o arm-linux-ld -Ttext 0x20000000 -o key.elf $^ arm-linux-objcopy -O binary key.elf $@ arm-linux-objdump -D key.elf > key.dis key.o : key.c arm-linux-gcc -c $< -o $@ start.o : start.S arm-linux-gcc -c $< -o $@ clean: rm *.o *.elf *.bin *.dis
将程序下载到内存运行
按下key1,LED1点亮,再次按下key1,LED1熄灭
按下key2,LED2点亮,再次按下key2,LED2熄灭