5.2440的按照中断编程
首先是打开底板的原理图,找到按键的信息:
可以找到四个按键:
可以看到四个按键对应的引脚是EINT1、EINT4、EINT2和EINT0. 然后在核心板原理图里去搜索这四个按键,可以看到下面的信息:
可以看到,按键中断与寄存器组GPF的引脚是互用的。所以接下来就是查看芯片手册里的GPF组寄存器的信息:重点是关注GPF控制寄存器:GPFCON
由于是按键,要配置成中断的方式,所以对应的GPF位设置为10=EINT[*]的方式。由上面知道要设置的位是EINT0、EINT4、EINT1和EINT2.
其实上面的这些设置就是中断源的设置。
代码:
上面就是初始化按键,也就是初始化中断源。
接下来是中断控制器的初始化:interrupt.c
由芯片手册知道,中断从发生到CPU响应的流程:
由于这里是按键中断,不用考虑SUBMASK,而且主要是讲按键中断的MASK操作,所以中断的模式MODE也不考虑和Priority保持为默认值。所以找到中断控制器的MASK寄存器:
它是由很多位构成的,每个位控制一种中断:
上面的信息知道对应的位如果是1,该中断会被屏蔽。由于我们要使用四个按键,对应的中断是EINT4、EINT2、EINT1和EINT0,所以要把这四位设置为0.但是这里需要注意的是[4]位控制了EINT4_7四个中断,所以要设置EINT4的时候,还需要在EINTMASK寄存器里进行相应的设置。
从上面知道,只有把该寄存器的第[4]位设置为0即可。
注意的是EINT4在EINTMASK寄存器里的设置必须在前面。
上面就完成了中断控制器的设置。
由于前面把中断给屏蔽了,现在就要把它打开,通过CPSR寄存器的I位:
重要位的解释:
可以看到只要将对应的位置为0就是打开中断。这里CPSR的末尾8位是属于control域的,我们使能中断也只是需要操作这8位。中断打开实现代码:
上面到这里才完成了中断的初始化。接下来是中断处理的部分。
中断处理:
保存环境的流程示意图:
可以看到,当中断产生的时候,系统会把处理完中断要跳转回来继续执行的位置lr-4的地址保存入lr寄存器里,用于保存环境。然后批量的保存现场的寄存器里的值:
stmfd sp!, {r0-r12, lr} /* 保护现场 */
这里的sp是堆栈指针,就是不r0-r12,13个寄存器的值和lr寄存器的值都保存到堆栈里。注意sp后面的!是指每一次的修改都将改变sp指针的值。
这样就保存好了现场,接下来就是中断处理程序的执行:
跳转到handle_int来处理不同的中断处理:
1.要判断产生中断的中断源,需要通过一个寄存器INTOFFSET,它的每一个位代表一种中断信号:
所以接下来定义一个值,把这个寄存器里的值读出来。
由按键的原理图:
从上图知道,当一号按键K1被按下的时候,产生的中断是EINT1,当二号按键K2被按下的时候,产生的是EINT4,当三号按键被按下的时候,产生的是EINT2,当四号按键被按下的时候,产生的是EINT0.这四种中断源对应的OFFSET的值如下图:
下面是通过switch语句来实现不同按键按下相应的中断处理程序:
上面就完成了按键中断处理程序,但是此时我们还不能进行编译执行,再回去看中断处理的流程图:
在这流程图中还有SRCPND和INTPND寄存器没有设置。这两个寄存器是干啥用的呢?先来看芯片手册:
原来这个寄存器的作用是把处理完的中断对应的中断位清0的,这样,下一次中断产生才会被相应而得到相应的处理。所以我们处理完按键中断后,也需要对相应的位进行清0操作。
该寄存器对应的位的信息:
INTPND寄存器也是同理的,INTPND寄存器对应的参数:
接着就是对上面两个寄存器对应的位进行清零操作:对于这两个寄存器要注意的是,如果我们想往对应的位写入0,需要将该位设置为1,这是跟其他寄存器不同的地方。
这里由于我们用到了EINT4产生的中断源,它是属于EINT4_7寄存器组的,所以我们也需要设置清除EINTPND寄存器。
同理就是往对应的位写入1就是清零。
最后实现中断清零的代码:
处理完中断后就是恢复现场,把保存在堆栈里寄存器的值全部恢复回来,只是现在lr寄存器要变成pc程序状态寄存器了。
到这里我们就完成了中断的设置工作,执行make进行编译操作,将bin文件烧写到开发板,发现LED灯不亮,就是说我们的程序还存在着问题。那么这问题究竟出在哪呢?
其实问题就出在没有初始化堆栈,因为刚开始初始化的堆栈是在SVC模式下的:
可以看到程序一开始就工作在SVC模式,而我们的按键中断是工作在irq模式的。我们需要这是工作在irq模式的堆栈,才能让程序正常运行。要设置系统工作在irq模式,需要将CPSR的模式位设置为10010:
实现代码:
这里的cpsr_c是CPSR寄存器的末尾8位:
这里设置的值为0xd2=0b 11010010,可以看到该值把中断打开了,而且还设置系统工作在irq模式。
最后的代码是:
我们给irq模式下的sp堆栈设置了值,接着给SVC模型下的sp堆栈设置了值。重新编译一下烧写到开发板,当我们按下相应的按键的时候,可以看到对应的LED灯亮了。