s5p6818裸机-irq中断

前言

本次学习的目的是通过按按键触发按键中断,调用相关的中断服务函数,实现蜂鸣器鸣响。通过裸机学习能使自己对SoC的运行环境,开发环境有更好的了解。

软件实现流程

1)在start.S启动汇编中实现中断向量表,及irq处理函数
2)实现irq中断结构体数组,irq通用中断服务函数注册函数(中断号和中断服务函数的联系)
3)实现gic中断控制器初始化函数
4)实现gpio初始化函数,复用-中断配置

流程具体

1、异常向量表和IRQ_Handler一般都在start.S里面编写,因为需要做一些中断触发时保护现场和恢复现场的工作。

_start:/*DDR范围:0x40000000~0x80000000 1GB*//*异常向量表 */ldr pc, =Reset_Handler      /* 复位中断 					*/	ldr pc, =Undefined_Handelr  /* 未定义中断 					*/ldr pc, =SVC_Handelr        /* SVC(Supervisor)中断 		*/ldr pc, =PrefAbort_Handler  /* 预取终止中断 					*/ldr pc, =DataAbort_Handler  /* 数据终止中断 					*/ldr pc, =NotUsed_Handler    /* 未使用中断					*/ldr pc, =IRQ_Handler        /* IRQ中断 					*/ldr pc, =FIQ_Handler        /* FIQ(快速中断)未定义中断 			*/
IRQ_Handler:ldr sp,=0x7FC00000 /*设置irq模式的sp指针 *//*保护现场 */push {lr}push {r0-r3,r12}   mrs r0, spsr   /*访问SPSR寄存器,保存cpsr */push {r0}
/****************************************************** */mrc p15,1,r1,c15,c3,0 /*读取GIC的CPU接口端基地址 GICC_CTLR*/ldr r0, [r1,#0xC]   /*基地址偏移0xC,访问GICC_IAR寄存器 *//*GICC_IAR能够获取到中断ID号 */push {r0,r1}cps #0x3           /*进入svc模式 */push {lr}       /*保存svc的lr寄存器 *///ldr r2, =system_irqhandler blx system_irqhandler            /*跳转到c程序的中断处理函数中,带上一个参数r0(中断ID)*/pop {lr}   /*lr出栈 */cps #0x2   /*进入irq模式 */pop {r0,r1}str r0, [r1,#0x10]  /*中断执行完成,把中断ID写入EOIR寄存器 *//*恢复现场 */pop {r0}msr spsr, r0  /*恢复cpsr */pop {r0-r3,r12}pop {lr}
/********************************** */subs pc, lr, #4 /*返回触发中断时,下一条指令的位置 */

其中恢复现场的subs pc, lr, #4 是因为cpu是三级流水线工作的,取址,译址,执行。比如当前第一条指令是执行,第二条指令是译址,第三条指令是取址,那么当中断触发时,pc所指向的是取址,而恢复现场则需要从第二条指令那里开始恢复即pc-4的位置。

2、实现irq中断结构体数组,(中断号和中断服务函数的联系)

/*中断服务函数的形式*/
typedef void (*system_irq_handler_t)(unsigned int giccIar,void *param);/*中断服务函数结构体*/
typedef struct _sys_irq_handle
{system_irq_handler_t irqhandler;    /*中断服务函数*/void *userParam;                    /*中断服务函数参数*/
}sys_irq_handle_t;static sys_irq_handle_t irqTable[160]; /*数组大小为160,每一个元素的下标对应一个中断ID*/

有了这个结构体数组,就实现了中断号和中断服务函数的联系了,下一步就是把中断服务函数往里面注册就可以了。

3、irq通用中断服务函数注册函数

/*给指定的中断号注册中断服务函数 */
void system_register_irqhandler(IRQn_Type irq, system_irq_handler_t handler, void *userParam)
{irqTable[irq].irqhandler = handler;irqTable[irq].userParam = userParam;
}

这个就是往结构体里面注册中断服务函数了,自己编写好最终的中断服务函数,作为参数handler往里面存。

4、上面start.S的IRQ_Handler会跳进这个函数,根据中断ID执行最终的中断服务函数

/*具体的中断服务函数*/
void system_irqhandler(unsigned int giccIar)
{unsigned int intNum = giccIar & 0x3FF;  /*GICC_IAR的bit[9:0]为中断ID*/if(intNum < NUMBER_OF_INT_VECTORS){irqNesting++;irqTable[intNum].irqhandler(intNum, irqTable[intNum].userParam);irqNesting--;}elsereturn;
}

5、gic的初始化
参考数据手册,得到需要用到的寄存器GICD_TYPER、GICD_ISCENABLERn、GICC_PMR、GICC_BPR、GICD_CTRL、GICC_CTRL、GICD_ISENABLERn、GICD_IPRIORITYRn,寄存器的具体作用我在下面代码里面也作了注释,或者去查看手册。

/*GIC初始化*/
void GIC_init(void)
{unsigned int i;unsigned int irqRegs;/*读取bit[0:4]为N,支持的中断ID最大值:(32(N+1)-1=159)*/irqRegs = (GIC->D_TYPER & 0x1F) + 1; /*关闭所有SGI,PPI,SPI中断*/for(i=0; iD_ISCENABLERn[i] |= 0xFFFFFFFF; /*设置支持32个优先级,即bit[7:0]=11111000*/GIC->C_PMR |= (0xFF << 3);  //GIC->C_PMR |= 0xFF;/*设置5级抢占优先级bit[2:0]=2,即所有中断优先级位都为抢占优先级*/GIC->C_BPR |= (2<<0);/*使能组0的中断分发控制*/GIC->D_CTRL |= (0x1<<0);/*使能组0的中断发送到CPU Core的中断请求信号*/GIC->C_CTRL |= (0x1<<0);
}/*使能指定中断,并设置优先级*/
void GIC_EnableIRQ(IRQn_Type IRQn, unsigned int pri)
{/*IRQn/32: 取到0~4寄存器里对应的寄存器*//*IRQn%32: 取到对应寄存器里相应的bit*/GIC->D_ISENABLERn[IRQn/32] |= (1<<(IRQn%32));GIC->D_IPRIORITYRn[IRQn/4] &= ~(0xFF<<((IRQn%4)*8));GIC->D_IPRIORITYRn[IRQn/4] |= (pri<<((IRQn%4)*8));      /*设置指定中断的优先级*///GIC->D_ITARGETSRn[21] &= (~(0xFF<<16));//GIC->D_ITARGETSRn[21] |= (0x1<<16);    /*设置指定中断的CPU接口*/
}

6、gpio的中断设置
通过查看数据手册得到需要使用的寄存器有GPIOXINTENB、GPIOXDETENB、GPIOXDETMODE0、GPIOXDETMODE1、GPIOXDETMODEEX、GPIOXDET,具体功能也是在下面代码的注释里面有说明

/*使能GPIO口的中断功能*/
void gpio_intEnable(GPIO_Type *base, int pin)
{base->GPIO_INTENB |= (1<GPIO_DETENB |= (1<GPIO_DETMODE0); /*0~15引脚*/}else{DetMode = &(base->GPIO_DETMODE1); /*16-31引脚*/pin_t -= 16;}switch(intmode){case GPIO_IntLowLevel:base->GPIO_DETMODEEX &= ~(1<GPIO_DETMODEEX &= ~(1<GPIO_DETMODEEX &= ~(1<GPIO_DETMODEEX &= ~(1<GPIO_DETMODEEX |= (1<GPIO_DET |= (1<

小结

总体来说整个中断的执行顺序大概是:按下按键 -> 触发irq中断信号 -> gic控制器 -> CPU -> 异常向量表 -> IRQ异常处理 -> 执行最终的中断服务程序


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部