1. 中断也是一种异常,可以出发FIQ或IRQ异常。
OK6410提供64个中断源,其中INT_EINT0~4是由外部信号触发的中断,其它都是由芯片内部信号触发的中断。
2. 外部触发中断,OK6410提供127个外部中断源,共划分为10组,其中第0组最受重视,在VIC中分配的5个外部中断源中的分配如下:
Group0的IO口占用的VIC中的4个中断源,而Group1--Group9共占用VIC中的一个中断源。
INT_EINT0--Group0[0--3]
INT_EINT1--Group0[4--11]
INT_EINT2--Group0[12--19]
INT_EINT3--Group0[20--27]
INT_EINT4--Group1~Group9
3. OK6410开发板中按键引脚分配
4. 中断配置过程
4.1 GPIO配置,先配置为中断功能,再配置中断产生何种信号才会被捕获。主要是五种,低电平,高电平,上升沿,下降沿或者两者均可, 第0组用EINT0CON0/EINT0CON1两个寄存器来设定。
/* 配置GPIO引脚为中断引脚 */
/* GPN0~5 设为中断引脚 */
GPNCON &= ~(0xfff);
GPNCON |= 0xaaa;
/* 设置中断触发方式为: 双边沿触发 */
EINT0CON0 &= ~(0xfff);
EINT0CON0 |= 0x777;
4.2 使能中断
中断开关分为3级,EINTxMask是临时性关闭中断,VICxINTENABLE是VIC控制器中的中断开关,CPSR中的I/F位是中断总开关。
5. 中断处理函数
IRQ中断处理发生后硬件完成以下工作,注意PC的跳转,当VE值不同时跳转到的地址不同,由此产生两种不同的中断处理方式,向量中断和非向量中断。
mrc p15,0,r0,c1,c0,0
orr r0,r0,#(1<<24) @ SET VE=1
mcr p15,0,r0,c1,c0,0
5.1 非向量中断(VE=0)
PC跳转到固定的地址去执行中断服务函数(ISR)。再判断具体是哪个中断源产生的中断,然后再调用具体的处理函数。
注意在S3C6410用32个地址连续的寄存器组成两个寄存器数组,用来保存VIC中对应的中断源的ISR入口函数地址。首地址分别是0x71200100和0x71300100,可以象指针数组一样来操作它们,数组的下标就是中断号。
当处理某个中断函数时,对应的VICxVECTADDR会自动拷贝到VICxADDRESS寄存器中,所以读取VICxVECTADDR就可以得到ISR的入口地址。
写任意值到VICxVECTADDR中可以清除当前中断。
5.2 向量中断(VE=1)
当VE=1时,IRQ发生后,PC直接跳转至对应的VICxVECTADDR指定的ISR入口地址执行。
5.3 区别
非向量中断由于跳转到固定地址0x00000018,所以保存现场/恢复现场的工作都在0x00000018地址的代码中执行。
fiq:
/* 1. 保存现场 */
ldr sp, =0x53000000
sub lr, lr, #4
stmdb sp!, {r0-r7, lr} /* lr就是swi的下一条指令地址 */
/* 2. 处理异常 */
bl do_fiq
/* 3. 恢复现场 */
ldmia sp!, {r0-r7, pc}^ /* ^表示把spsr恢复到cpsr */
void do_irq(void)
{
int i = 0;
void (*the_isr)(void);
if (VIC0IRQSTATUS)
{
the_isr = VIC0ADDRESS;
/* 2.1 分辨是哪个中断 */
/* 2.2 调用它的处理函数 */
/* 2.3 清中断 */
the_isr();
EINT0PEND = 0x3f; /* 清中断 */
VIC0ADDRESS = 0;
}
}
IRQ发生后,自动跳转执行函数eint0_3_irq或者eint4_11_irq。
void irq_init(void)
{
/* 配置GPIO引脚为中断引脚 */
/* GPN0~5 设为中断引脚 */
GPNCON &= ~(0xfff);
GPNCON |= 0xaaa;
/* 设置中断触发方式为: 双边沿触发 */
EINT0CON0 &= ~(0xfff);
EINT0CON0 |= 0x777;
/* 使能中断 */
EINT0MASK &= ~(0x3f);
//VIC0INTSELECT |=0x20; /*key1~4 FIQ, key5~6 IRQ*/
//VIC0INTENABLE |= (0x20);
/* 在中断控制器里使能这些中断 */
VIC0INTENABLE |= (0x03); /* bit0: eint0~3, bit1: eint4~11 */
VIC0VECTADDR0 = eint0_3_irq; /* 用户按下key时,CPU就会自动的将VIC0VECTADDR0的值赋给VIC0ADDRESS并跳转到这个地址去执 */
VIC0VECTADDR1 = eint4_11_irq;
}
void eint0_3_irq(void)
{
int i;
__asm__(
"sub lr, lr, #4\n"
"stmfd sp!, {r0-r12, lr}\n"
:
:
);
printf("auto eint0_3_irq\n\r"); /* K1~K4 */
for (i = 0; i < 4; i ++)
{
if (EINT0PEND & (1<
参考: 6410中断控制详解
你可能感兴趣的:(ARM-Linux)