gpio中断:
一,启动时的操作
1.首先当然是操作cpsr寄存器来开启中断模式下的IRQ中断(因为在BL0中的程序将IRQ中断关闭了)
2.设置中断模式下的栈地址
3.中断前的环境保存和中断后的环境恢复
代码如下():
.global Reset
Reset:
@关闭看门狗省略,bl0启动的时候已经关闭
@msr cpsr_c,#0xd2 @进入中断模式 arm状态 禁止fiq irq
@ldr sp,=0x22000000 @栈指向sdram的地址
@msr cpsr_c,#0xdf @进入系统模式 arm状态 禁止fiq irq
@ldr sp,=0x23000000 @栈指向sdram的地址
ldr sp, =0x40000000
msr cpsr_c,#0x53 @0x5f @系统模式下开irq中断
bl init_irq
ldr lr,=halt_loop @设置用于当前状态的返回地址
@ldr sp,=0x24000000
ldr pc,=main @main里面为死循环闪灯
halt_loop:
b halt_loop
.globl IRQ_Handle
IRQ_Handle:
ldr sp, =0xD0037F80 @0xD0037F80 是中断向量表的栈底
sub lr , lr , #4 @计算历史状态的返回地址
stmdb sp! , {r0-r12,lr} @保存历史状态的寄存器值
ldr lr,=int_return @设置用于当前状态的返回地址
ldr pc,=EINT_Handle
int_return:
ldmia sp! , { r0-r12,pc }^ @ ^表示将spsr的值复制到cpsr中去
二,gpio中断的初始化,即函数init_irq()
1.初始化中断向量表
2.中断跳转函数的定义,此处为EINT_Handle函数
3.GPIO中断的配置
代码如下:
void init_irq(void)
{
//init EINT3
Init_Vevtor(); //初始化中断向量表
//清除中断使能(禁止中断)
VIC0INTENCLEAR = 0xffffffff;
VIC1INTENCLEAR = 0xffffffff;
VIC2INTENCLEAR = 0xffffffff;
VIC3INTENCLEAR = 0xffffffff;
//设置所有中断源为IRQ中断
VIC0INTSELECT = 0x0;
VIC1INTSELECT = 0x0;
VIC2INTSELECT = 0x0;
VIC3INTSELECT = 0x0;
//清除每个中断组服务程序入口地址,即四个VICxINTADDR寄存器
*((unsigned long*)(0xF2000F00))=0;
*((unsigned long*)(0xF2100F00))=0;
*((unsigned long*)(0xF2200F00))=0;
*((unsigned long*)(0xF2300F00))=0;
#if 0 //EINT中断配置
GPH0CON|=(0XF<<12); //选择EINT3中断功能
EXT_INT_0_CON|=(0X2<<12); //EINT3下降沿中断
EXT_INT_0_MASK&=(~(1<<3)); //使能EINT中断
VERCTOR_ADDR0(3)=EINT_Handle; //中断处理函数
EXT_INT_0_PEND|=(1<<3); //清除中断标志 不知道为什么一开机中断标志就置位了
VIC0INTENABLE|=(1<<3); //中断向量表VIC0 EINT3使能
//*((unsigned long*)(0xF200020C))=0; //设置优先级为0
#endif
GPD0CON|=(GPD0CON2); //INT FUNCTION
GPD0_INT_CON|=(GPD0_INT_CON2);//both edge triggered GD0_2,GD0_3
GPD0_INT_MASK&=(~(1<<2));
VERCTOR_ADDR0(30)=EINT_Handle; //set interrupt address
//VERCTOR_PRIORITY0_30=0; //set priority
GPD0_INT_PEND|=(1<<2);
VIC0INTENABLE = 1<<30; //set int enable
}
EINT外部中断只要把上述函数init_irq()中的外部中断的配置替换下就行了
代码链接:https://pan.baidu.com/s/1HV5uAAtVgl5vkcMsS5k83w