6.6410和210的按键中断编程
首先是打开6410底板原理图:
可以看到OK6410有六个按键:
可以看到OK6410的六个按键对应的引脚是KEYINT1、KEYINT2、KEYINT3、KEYINT4、KEYINT5和KEYINT6。接着在核心板的原理图里搜索这个词:
可以看到按键中断与GPN系列寄存器的引脚是互用的,接着就是在芯片手册里查看有关GPN系列寄存器的信息,重点是关注GPN控制寄存器:GPNCON:
这里我们使用到的按键对应的中断,需要配置成中断的方式,对应的GPN位设置为10,中断功能,即需要将KEYINT1-6设置为中断功能的,即是将GPNCON对应的前12位设置为101010101010即可。这样就把对应的GPN0-5设置为中断位。实现代码:
上面我们完成了按键的初始化,这样就把六个按键对应的位设置为外部中断的功能了。
接下来就是中断的初始化了。
1.设置按键中断是发生在下降沿,也就是下降沿触发的方式,即低电平,按键弹开是上升沿,也就是高电平。
这里需要寄存器EINT0CON0:
由原理图知道KEYINT1-KEYINT6对应的中断位是XEINT0-XEINT5,由上面设置从下降沿触发:
设置好了下降沿触发,接着就是把先前屏蔽的功能去掉,就是使能中断:
屏蔽寄存器:
这里我们需要将对中断位EINT0-EINT5的屏蔽功能给去掉,要不然,即使发生了中断也不会送到CPU。这是为了方便,就不一一去设置,直接将该寄存器赋值为0,就是全部中断去掉屏蔽:
取消屏蔽外部中断后,就是使能外部中断的操作:
上面两个寄存器就是使能中断的,每一位控制一种中断源,在系统复位之后默认的值是0,如果需要使能某个中断,就需要将对应的位设置为1=Interrupt enabled。
从上面知道,我们的外部中断0-3是属于中断源0的,外部中断4-11是属于中断源1的。所以要使能六个按键的外部中断,需要使能0号中断源和1号中断源,该中断源是属于VIC0寄存器组的,就是往VIC0INTENABLE的0位和1位写入1即可,代码实现:
这样使能外部中断也完成了。
接下来设置CPSR程序状态寄存器,来打开总的中断控制,因为前面的学习中是把它关闭的。
到这里如果按照2440的非向量中断的设置到这里就结束,但是在6410里还没有,因为6410采用的是向量中断方式。
首先来看看非向量中断方式的流程图:
上面就是非向量中断的中断处理流程,当中断产生的时候,会跳转到对应的统一的入口,去执行对应的中断处理程序,大部分的工作都是软件来完成的。
而6410的向量中断,很大部分的工作是硬件来完成的,这样速度会更快,原理图:
上面就是向量中断的原理。
所以接下来就是在中断初始化的时候,把对应的中断处理程序(就是处理程序的函数名字)安排到对应的寄存器里。接下来就是该操作:先找到对应的寄存器组:
可以看到属于VIC0组的有32个寄存器,属于VIC1组的也有32个寄存器,刚好64寄存器,对应64个中断源。按键1对应的是EINT0,也就是对应寄存器0x71200100.
代码:
上面就是按键的中断处理程序。但是在6410默认是没有使能向量中断的,它是先下兼容,默认是非向量中断的,所以6410要使用向量中断需要使能。注意210就不需要使能了。在CP15的c1寄存器的24位控制的。6410使能代码:
__asm__(
"mrc p15,0,r0,c1,c0,0\n"
"orr r0,r0,#(1<<24)\n"
"mcr p15,0,r0,c1,c0,0\n"
"mrs r0,cpsr\n"
"bic r0, r0, #0x80\n"
"msr cpsr_c, r0\n"
:
:
);
上面就是使能向量中断的操作,到这里才完成了6410的中断初始化的操作。
最后就是中断处理了。
步骤:
- 保存环境
- 中断处理
- 清除中断
- 恢复环境
1.保存环境:
__asm__(
"sub lr, lr, #4\n"
"stmfd sp!, {r0-r12, lr}\n"
:
:
);
2.中断处理:
3.是清中断:
清中断对应的寄存器:
该寄存器当相应的中断产生的时候,对应的中断位会被置1.从该寄存器的NOTES知道,如果往对应的中断位写入1,则就是清除中断。这里为了方便,我们写入全1,清除所有的中断。
我们前面知道每一种向量中断对应一个寄存器
VIC0组的寄存器:
VIC1组寄存器:
上面就是64中断源对应的64个寄存器,在这些寄存器的后面有寄存器VICxADDRESS:
这种寄存器有两个,VIC0ADDRESS和VIC1ADDRESS.例如当VIC0的一个串口中断产生的时候,系统除了会调用对应的处理函数外,还会把中断处理程序的地址保存到VICxADDRESS寄存器里面。
当中断处理完后,要把这两个寄存器清零:
这样就完成了中断处理程序了。
4.最后一步就是清中断:
"ldmfd sp!, {r0-r12, pc}^ \n"
到这里才完成了中断处理程序的步骤,最后的部分代码如下:
…
注意到这里虽然中断的处理程序完成了,但是还不能烧写到开发板。这是因为跟2440的情况一样,我们的start.S里只有对svc模式的堆栈进行初始化,没有对irq模式的堆栈进行初始化。所以最后我们还得来对irq的堆栈进行初始化:
可以看到程序一开始就工作在SVC模式,而我们的按键中断是工作在irq模式的。我们需要这是工作在irq模式的堆栈,才能让程序正常运行。要设置系统工作在irq模式,需要将CPSR的模式位设置为10010:
实现代码:
这里的cpsr_c是CPSR寄存器的末尾8位:
这里设置的值为0xd2=0b 11010010,可以看到该值把中断打开了,而且还设置系统工作在irq模式。
最后的代码是:
我们给irq模式下的sp堆栈设置了值,接着给SVC模型下的sp堆栈设置了值。重新编译一下烧写到开发板,当我们按下相应的按键的时候,可以看到对应的LED灯亮了。如果按下第一下可以亮,接着按按键没有反应,很有可能是堆栈没有设置好。
这就是6410的中断处理流程,对于210也是一样的操作,只是210默认是打开向量中断的,不必去设置打开,其他都是一样的。