5.2440的按照中断编程

5.2440的按照中断编程

首先是打开底板的原理图,找到按键的信息:

可以找到四个按键:

5.2440的按照中断编程_第1张图片

可以看到四个按键对应的引脚是EINT1、EINT4、EINT2和EINT0. 然后在核心板原理图里去搜索这四个按键,可以看到下面的信息:

5.2440的按照中断编程_第2张图片

可以看到,按键中断与寄存器组GPF的引脚是互用的。所以接下来就是查看芯片手册里的GPF组寄存器的信息:重点是关注GPF控制寄存器:GPFCON

5.2440的按照中断编程_第3张图片

5.2440的按照中断编程_第4张图片

由于是按键,要配置成中断的方式,所以对应的GPF位设置为10=EINT[*]的方式。由上面知道要设置的位是EINT0、EINT4、EINT1和EINT2.

5.2440的按照中断编程_第5张图片

其实上面的这些设置就是中断源的设置。

代码:

5.2440的按照中断编程_第6张图片

上面就是初始化按键,也就是初始化中断源。

接下来是中断控制器的初始化:interrupt.c

由芯片手册知道,中断从发生到CPU响应的流程:

5.2440的按照中断编程_第7张图片

由于这里是按键中断,不用考虑SUBMASK,而且主要是讲按键中断的MASK操作,所以中断的模式MODE也不考虑和Priority保持为默认值。所以找到中断控制器的MASK寄存器:

5.2440的按照中断编程_第8张图片

它是由很多位构成的,每个位控制一种中断:

5.2440的按照中断编程_第9张图片

5.2440的按照中断编程_第10张图片

上面的信息知道对应的位如果是1,该中断会被屏蔽。由于我们要使用四个按键,对应的中断是EINT4、EINT2、EINT1和EINT0,所以要把这四位设置为0.但是这里需要注意的是[4]位控制了EINT4_7四个中断,所以要设置EINT4的时候,还需要在EINTMASK寄存器里进行相应的设置。

5.2440的按照中断编程_第11张图片

从上面知道,只有把该寄存器的第[4]位设置为0即可。

5.2440的按照中断编程_第12张图片

注意的是EINT4在EINTMASK寄存器里的设置必须在前面。

上面就完成了中断控制器的设置。

由于前面把中断给屏蔽了,现在就要把它打开,通过CPSR寄存器的I位:

5.2440的按照中断编程_第13张图片

重要位的解释:

5.2440的按照中断编程_第14张图片

可以看到只要将对应的位置为0就是打开中断。这里CPSR的末尾8位是属于control域的,我们使能中断也只是需要操作这8位。中断打开实现代码:

5.2440的按照中断编程_第15张图片

上面到这里才完成了中断的初始化。接下来是中断处理的部分。

中断处理:

5.2440的按照中断编程_第16张图片

保存环境的流程示意图:

5.2440的按照中断编程_第17张图片

可以看到,当中断产生的时候,系统会把处理完中断要跳转回来继续执行的位置lr-4的地址保存入lr寄存器里,用于保存环境。然后批量的保存现场的寄存器里的值:

stmfd sp!, {r0-r12, lr} /* 保护现场 */

这里的sp是堆栈指针,就是不r0-r12,13个寄存器的值和lr寄存器的值都保存到堆栈里。注意sp后面的!是指每一次的修改都将改变sp指针的值。

这样就保存好了现场,接下来就是中断处理程序的执行:

跳转到handle_int来处理不同的中断处理:

  1. 判断产生中断的中断源
  2. 根据中断源执行相应的中断处理程序。

1.要判断产生中断的中断源,需要通过一个寄存器INTOFFSET,它的每一个位代表一种中断信号:

5.2440的按照中断编程_第18张图片

5.2440的按照中断编程_第19张图片

所以接下来定义一个值,把这个寄存器里的值读出来。

由按键的原理图:

 

5.2440的按照中断编程_第20张图片

从上图知道,当一号按键K1被按下的时候,产生的中断是EINT1,当二号按键K2被按下的时候,产生的是EINT4,当三号按键被按下的时候,产生的是EINT2,当四号按键被按下的时候,产生的是EINT0.这四种中断源对应的OFFSET的值如下图:

5.2440的按照中断编程_第21张图片

下面是通过switch语句来实现不同按键按下相应的中断处理程序:

5.2440的按照中断编程_第22张图片

上面就完成了按键中断处理程序,但是此时我们还不能进行编译执行,再回去看中断处理的流程图:

/5.2440的按照中断编程_第23张图片

在这流程图中还有SRCPND和INTPND寄存器没有设置。这两个寄存器是干啥用的呢?先来看芯片手册:

5.2440的按照中断编程_第24张图片

原来这个寄存器的作用是把处理完的中断对应的中断位清0的,这样,下一次中断产生才会被相应而得到相应的处理。所以我们处理完按键中断后,也需要对相应的位进行清0操作。

该寄存器对应的位的信息:

5.2440的按照中断编程_第25张图片

5.2440的按照中断编程_第26张图片

INTPND寄存器也是同理的,INTPND寄存器对应的参数:

5.2440的按照中断编程_第27张图片

5.2440的按照中断编程_第28张图片

5.2440的按照中断编程_第29张图片

接着就是对上面两个寄存器对应的位进行清零操作:对于这两个寄存器要注意的是,如果我们想往对应的位写入0,需要将该位设置为1,这是跟其他寄存器不同的地方。

这里由于我们用到了EINT4产生的中断源,它是属于EINT4_7寄存器组的,所以我们也需要设置清除EINTPND寄存器。

5.2440的按照中断编程_第30张图片

5.2440的按照中断编程_第31张图片

同理就是往对应的位写入1就是清零。

最后实现中断清零的代码:

处理完中断后就是恢复现场,把保存在堆栈里寄存器的值全部恢复回来,只是现在lr寄存器要变成pc程序状态寄存器了。

到这里我们就完成了中断的设置工作,执行make进行编译操作,将bin文件烧写到开发板,发现LED灯不亮,就是说我们的程序还存在着问题。那么这问题究竟出在哪呢?

    其实问题就出在没有初始化堆栈,因为刚开始初始化的堆栈是在SVC模式下的:

可以看到程序一开始就工作在SVC模式,而我们的按键中断是工作在irq模式的。我们需要这是工作在irq模式的堆栈,才能让程序正常运行。要设置系统工作在irq模式,需要将CPSR的模式位设置为10010:

5.2440的按照中断编程_第32张图片

实现代码:

这里的cpsr_c是CPSR寄存器的末尾8位:

5.2440的按照中断编程_第33张图片

这里设置的值为0xd2=0b 11010010,可以看到该值把中断打开了,而且还设置系统工作在irq模式。

最后的代码是:

5.2440的按照中断编程_第34张图片

我们给irq模式下的sp堆栈设置了值,接着给SVC模型下的sp堆栈设置了值。重新编译一下烧写到开发板,当我们按下相应的按键的时候,可以看到对应的LED灯亮了。

你可能感兴趣的:(5.2440的按照中断编程)