您的位置:首页 > 编程语言

从程序的执行过程的角度去编写IRQ中断框架代码

2015-08-12 23:44 579 查看
1.从u-boot跳到0x40000000执行start.S,首先保存lr至r5以便边返回u-boot交互界面
2.初始化包括led灯的初始化和中断初始化:
1)led灯初始化应该实现GPIO引脚为输出模式,输出的电平为1



2)中断的初始化包括:
a.GPIO口控制器初始化(初始化按键的IO口),应该设为中断模式;



b.外部中断控制器初始化EXT_INT,初始化中断的触发方式:(高/低)电平触发还是(上升/下降)边沿触发,初始化为不屏蔽该类型中断(设置MASK寄存器),将中断标志位写零;



c.初始化初始化向量中断控制器VIC0,A8支持93种类型的中断,分为四组:VIC0,VIC1,VIC2,VIC3,每一类型的中断对应与某一组中的一个通道(外部中断[16:31]为二级中断,共用VIC0的第16号中断通道)。向量中断控制器要做的第一个工作是:将该通道使能位清零(通过VIC0INTENCLEAR寄存器设置),其次由于CPU只能识别IRQ和FRQ两种类型的中断,所以需要为这个中断贴上IRQ或者FRQ的标签(设置VIC0INTSELECT寄存器),然后使能这一个中断(VIC0INTENABLE),每个中断通道中都有其对应的一个32位的VIC0VECTADDRn寄存器,这个寄存器初始化时用来保存中这个中断的中断处理程序标号(地址),当中断发生时,这个寄存器的内容会被同步到VIC0ADDRESS寄存器中,而A8会根据这个寄存器的内容跳到指定的中断处理程序,但是A8不会直接从VIC0ADDRESS寄存器拿值,而是先对另外一个只读寄存器的内容进行判断(由软件程序实现),这个寄存器是VIC0IRQSTATUS,这个寄存器会对VIC0ADDRESS寄存器进行判断里面的内容是否为零,如果里面的内容是一个地址,那么VIC0IRQSTATUS不为零,这时A8可以拿走VIC0ADDRESS寄存器里面的地址赋值给pc,即跳到中断处理子程序(这里为Eint16_31_isr)中去,在初始化的时候我们需要将VIC0ADDRESS寄存器的内容清零,最后我们还要做一个工作就是使能这一个中断通道(设置VIC0INTENABLE对应通道的位
)。总的来说,在初始化响亮中断控制器这一步中,我们要初始化的内容只有5个:设置VIC0INTENCLEAR寄存器,给中断贴标签IRQ还是FRQ,设置对应通道的VIC0VECTADDRn寄存器(内容为中断子程序的地址),初始化VIC0ADDRESS寄存器内容为零,使能这个中断通道。

(拓展:有VIC0,VIC1,VIC2,VIC3,A8是怎么知道究竟是哪一组产生中断的呢?其实A8通过遍历每一组的VICnIRQSTATUS来确定是哪一组产生的中断。)



d.状态寄存器的中断使能,标志位I=0,F=0,允许IRQ和FRQ中断



3.中断响应过程包括:保护现场、真正的中断处理、恢复现场
1)保护现场包括3部分:模式切换、PC跳转、保存通用寄存器的内容

首先是模式切换,从SVC模式切换到IRQ模式,将当前程序状态寄存器CPSR的

内容保存到IRQ模式的SPSR中,设置当前程序状态寄存器CPSR中相应的位,接着实现pc的跳转,这个过程包括:把pc的值储存到lr寄存器中,如果是处理IRQ中断,pc←0x18(iROM前32个字节是一个中断向量表)实现跳转,iROM中的0x18中内容是让pc跳到iROM中的0x30去执行一段代码,由于iROM内容已经被三星固化且该存储器属性为只读,所以三星需要向用户提供一个用户自定义的异常向量表,而且提供一个机制让iROM的中断向量表可以与iRAM用户定义的中断向量表可以一一对应,所以当pc执行iROM向量表后会跳往iROM后面的相对应的一段程序代码,这个代码会读取iRAM中0xd0037418(中断子程序标号)的内容,然后就从iROM中跳到中断子程序处执行。相应地,如果是FIQ中断,pc先会跳转到iROM中的0x1c处,然后再往后跳转,读取iRAM中0xd003741c(FIQ中断子程序的标号存在这里)的内容,然后再从iROM中跳到FIQ中断子程序进行处理。所以用户还需要初始化一个写进iRAM的中断向量表(向量表保存的内容是不同异常中断处理程序的标号,这里区别中断处理子程序即真正的中断处理,中断处理程序是一个大概念,包括:保护现场、中断处理子程序(如你要实现中断就亮一盏灯,点灯实验就写在中断处理子程序中)以及恢复现场),为了把底层封装起来,这个可以用汇编语言编写进_start:中。到此,我们已经清楚了模式切换和pc跳转的具体过程,这两个过程都是通过硬件实现的,只有保护现场的第三步:保存通用寄存器的内容由用户用程序实现,由于我们中断处理完后仍然要跳回原来的地方继续执行程序,所以我们需要保存pc的内容以便到时候回到中断前的地方,前面已经说过硬件实现pc跳转的时候已经把pc内容保存到了lr中,由于流水线的原因,我们需要将lr自减4个字节,即:sub
lr,lr,#4,然后在和r0-r15一起压进栈中保存起来(stmfd sp!,{r0-r12,lr})。至此,终于完成了保护现场的工作。



2)真正的中断处理(中断处理子程序),这部分在保存现场后需要进行一步判断,即判断前面提到的VIC0IRQSTATUS寄存器是否为0,如果非零,则pc会读取VIC0ADDRESS寄存器的内容(中断子程序的地址)跳转到真正的中断处理,如果是0,也就是说VIC0ADDRESS寄存器的内容为0,pc不会跳转,否则会回到0x0中,于是堆栈里面的东西弹出,恢复现场,回到原来程序被打断的地方。真正的中断处理才是我们想要关注,例如如果我们要实现一个中断点灯,那么点灯程序就可以在中断子程序中实现。但是,在这里需要注意,在s5pv210核心板中,外部中断16-31在向量控制器中共用一个通道16,即外部中断16-31为二级中断,所以在中断处理子程序中仍然需要进一步判断究竟是哪一个外部中断,这个我们可以用几个if语句或switch语句读取EXT_INT_2_PEND寄存器的内容就可以确定具体的外部中断了。确定具体中断来源后,我们还要把PEND位清零,同时把VIC0ADDRESS寄存器内容清0,这样才能开始编写真正的中断处理程序了。



3)恢复现场,这是中断处理程序的最后一步,我们要做的工作当然就是把通用寄存器和lr出栈,恢复到原理的状态,可以使用:ldmfd sp!,{r0-r12,pc}^,^是一个预处理,可以实现模式的切换。

以下是中断处理程序:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息