历史上的今天
今天是:2025年04月26日(星期六)
2019年04月26日 | S3C2440开发板裸机程序系列08—中断控制
2019-04-26 来源:eefocus
1. 概述
最近刚刚在TQ2440上面调通了ADXL345的I2C控制,可通过串口和TFT屏查看XYZ三个轴倾角变化,本来打算把TQ2440上面的I2C控制详细解说一下,但是还跳了2个知识点:中断和I2C协议。所以还要等我补充完这2个知识点再说。(I2C协议要从51单片机说起,后面总结时再谈吧)
从程序的执行过程来说,可以分为:正常执行,跳转执行(Arm汇编是B和BL指令,B指令不返回),中断处理。
从嵌入式控制的要求来说,一个嵌入式装置要完成大量的数据采集、数据变换、外设控制等功能,这些子功能的实现一般分为:查询方式和中断方式。显然中断方式可以提高处理器利用率,提高系统实时性。
S3C2440的中断包括快速中断FIQ和外部中断IRQ。因为FIQ模式有更多的私有寄存器,减少了模式切换过程中寄存器入栈和出栈的时间,所以FIQ执行效率更高。
通过INTMODE寄存器的设置,可以将某个中断定义为FIQ或者IRQ。如下图所示:


INTMODE初始值默认是IRQ。这里只讲IRQ,并且不讨论中断优先级设置问题。
下面从中断源与中断屏蔽、中断函数和执行过程、中断编程例子等几个方面进行展开。
2. 中断源与中断屏蔽
S3C2440处理器的中断处理流程见datasheet,如下。

入口,即中断源,有2种,with sub-register和without sub-register。
出口,也有2种,IRQ或FIQ,这个前面已经说过了。
对于with sub-register的中断源,需要先经过SUBMASK过滤。后面都要经过SRCPND,然后是MASK过滤,再然后是优先级Priority过滤到达INTPND,再送CPU处理。
S3C2440处理器的中断控制器支持60个中断源,如下:


中断的开关由几个寄存器来控制,并且初始状态(即默认)都是关闭的。先来了解一下都有哪些控制中断开关的寄存器设置。
经总结,共有4个地方设置中断的开与关:
a.当前程序状态寄存器CPSR和备份程序状态寄存器SPSR。在第6位和第7位,即F位控制FIQ中断是否允许响应,I位控制IRQ是否允许响应。这个寄存器设置主要是在启动程序中进行才有可能设置。用户编程可不考虑。
b.INTSUBMSK寄存器,它对应着上图的次级源这15个源,对应着设置INTSUBMSK[0:14],后面[15:31]没有用到。设置1是屏蔽,0是中断可用,初始都是1,即屏蔽状态。
c. INTMSK寄存器,它对应上图的这32个源,INTMSK[0:31]每个位对应一个。同理,设置1是屏蔽,0是中断可用,初始都是1,即屏蔽状态。
d.从上图的源和次级源的图中看出,EINT4_7和EINT8_23没有在次级源中,这么多外部中断源在次级源中也放不下了,所以又单独弄了个EINTMASK寄存器。在Datasheet中,这个寄存器没有在中断控制器Interrupt Controller中讲,而是放在了输入输出端口IO Ports中,如下图:

前4位保留,这样EINTn就和NINTMASK的位号对应上了。挺巧妙的。
下面再说中断触发的标志,怎么体现出某个中断发生了呢?再看上面的中断处理流程图,有这2个寄存器:SRCPND和SUBSRCPND,如下图。它们的各位是指示各中断源是否发生中断的指示标志。只要有中断发生,对应的位就置1。


其实,还有1个专门外部EINT的设置,EINTPEND寄存器,该寄存器仍然是在输入输出端口IO Ports章节里讲的。同上面的EINTMASK一样,前4位没用,[4:23]各位对应着EINT4—EINT23.

SRCPND、SUBSRCPND和EINTPEND 有些区别,比如串口0的中断,对于接收和发送中断分别是INT_RXD0和INT_TXD0,这2个中断发生时,SUBSRCPND[0:1]这2位要置1,并且SRCPND[28]这1位也置1。再比如,对应ENIT5发生中断时,EINTPEND[5] 置1,SRCPND[4]也置1。
刚才提到的那3个屏蔽寄存器INTMSK、INTSUBMSK和EINTMASK,与挂起寄存器道理是一样的:2个地方都有的,必须2个地方都解除屏蔽,这个中断才真的可以使用了。
3. 中断函数和执行过程
再看上面的中断处理流程图,如果某个中断没有屏蔽,发生中断后就会到达INTPND,这个寄存器某一位置1后,CPU就要进行处理了。中断挂起寄存器不再分源、次级源和外部中断,因此只1个寄存器--INTPND。它来告诉CPU有中断到来了。
总结一下这几个寄存器:
中断屏蔽寄存器:INTMSK、INTSUBMSK和EINTMASK。有3个,分别对应源、次级源和外部中断,设置哪一位为0则哪一位就使能中断。
中断源挂起寄存器:SRCPND、SUBSRCPND和EINTPEND。也有3个,分别对应源、次级源和外部中断,哪个源发生中断了,CPU就自动设置相应的位为1。
中断挂起寄存器:INTPND。只有1个。具体确认是哪个中断发生了,还要查询SUBSRCPND和EINTPEND。
此外:INTOFFSET寄存器。存的是0—31这个范围内的数值,对应着源的顺序号。这个主要是为了便于查询并进入相应的中断处理子程序中。
下面说中断处理的问题:
a.中断处理子程序做哪些必要的工作。
b.怎样自动处理中断处理子程序,包括进入和退出。
中断处理子程序必要的工作是:清中断标志位。这是为了下一次发生相同中断时还能处理,不是一锤子买卖。
怎样清中断? 哪一位置1了,就再置一次1。因此,SRCPND和INTPND必然是要清理的,此外SUBSRCPND和EINTPEND根据具体情况判断是否需要清理。
中断处理函数是特殊的子函数,因为它不需要在主函数中明确的调用。因此,使用ads中使用了关键字__irq 来表明这个函数是中断处理程序。__irq 发挥了下面2个主要作用:
a.中断发生时,自动保存所有需要保存的寄存器;
b.中断返回时,自动计数返回地址,自动进行CPSR寄存器状态的恢复。
各类型的中断处理程序的入口地址是固定的,这个工作是启动程序中完成。入口地址就是一个32位的寄存器,这些32位寄存器里放的是中断处理函数的地址。因此,当编写完中断处理程序后,就需要把该程序的起始地址(或函数句柄)填写到那个32位寄存器中。
程序中这样处理:
pISR_EINT0 = (unsigned int)Eint0_Isr ;
pISR_EINT1 = (unsigned int)Eint1_Isr ;
pISR_EINT2 = (unsigned int)Eint2_Isr ;
pISR_EINT4_7 = (unsigned int)Eint4_7_Isr;
其中,pISR_EINT0,pISR_EINT1 ,pISR_EINT2 ,pISR_EINT4_7 是中断源入口地址,它是根据中断起始地址+偏移量,提前计算好的地址,放在2440addr.h文件供C源程序使用。
Eint0_Isr,Eint1_Isr,Eint2_Isr,Eint4_7_Isr 是编写的中断处理函数。
4. 中断编程例子
两个例子:按键中断和定时器中断。
4.1按键中断
按键触发LED亮1秒钟。按键触发即外部中断触发,有高电平触发、低电平触发、边沿触发等,有EXINTn寄存器进行设置,这里采用默认值,即低电平触发。

如图所示,正好按下时为低电平,触发外部中断。
K1 -- EINT1 -- GPF1
K2 -- EINT4 -- GPF4
K3 -- EINT2 -- GPF2
K4 -- EINT0 -- GPF0
所以初始化时需要设置GPF0,GPF1,GPF2,GPF4为外部中断模式。
主程序做一些设置,然后就while(1);循环。
这些设置包括:Led和Key的GPIO状态设置,4个key中断位的使能中断设置,设置中断入口地址。
4.2 定时器中断
定时器Timer0初始化为1秒钟一次。
主程序中定义一个全局变量flag(需要加volatile关键字),Timer0中断处理程序中引用这个flag外部变量,每隔1sec进入中断处理程序后,就将flag取反。主程序根据flag值,设置Led2的亮灭。
主程序如下:
#include "ledflow.h"
#include "isrservice.h"
#include "timer.h"
void IO_Init(void) ;
volatile unsigned int flag = 0 ;
int Main()
{
IO_Init() ;
while(1)
{
if(flag )
{
Led2_On() ;
}
else
{
Led2_Off() ;
}
}
return 0;
}
void IO_Init(void)
{
Led_Init() ;
Timer0_Init() ;
Timer0_Interrupt_Init() ;
Isr_Init() ;
}
史海拾趣
|
我在控制面板扫描蓝牙设备能扫描到,可以当WINCESLEEP起来后,再在控制面板扫描时,就扫描不到了,并弹出对话框“BLUETOOTH HARDWARE ERROR 10050。。。。。。”有哪位兄弟遇到过这样的情况呀,是哪一块把连接断开了吗?请多多赐教呀!… 查看全部问答> |
|
谁有amx中控的编程软件和说明书?我去AMX公司,他们老板说网上下载,可是AMX的网站的下载在维护,不知那位哥们姐们有这块的编程软件和说明书,给个下载地址,谢谢… 查看全部问答> |
|
请问下如何通过CPU,来控制电压的大小? 意思就是说CPU给出如0101...的命令,应该怎么设计电路,或是有什么器件,可以使到这些命令可以控制电路中某个点电压的大小。… 查看全部问答> |
|
我想用LM3S8962驱动VS1003,但是8962的SPI被SD卡和OLED占用了,我打算用GPIO模拟SPI驱动VS1003,我是按照TI 最新的StellarisWare里的SoftSSI配置的GPIO,从icdev下了VS1003的驱动,配置好有没有听到正弦波,检测CLK好像也不对,请高手给指点一下吧 ...… 查看全部问答> |
|
在iar编译工具中,内置了一些内部函数,也就是Intrinsic.h头文件,里面的许多函数有些可以加快编写速度,有些可以指定变量的存放位置,还有些可以实现复杂的功能,但是我也只是了解其中的一些,请问各位谁有内部函数的讲解可以拿出来分享一下,感激 ...… 查看全部问答> |
|
毕业后,找了个测试工作,觉得没前途,于是想抓紧时间学点别的。本人水平有限,听人说这样很好实现,指标要求不高,主要是锻炼一下。找了好多资料,买了个最小系统,和tft屏幕。其他的打算自己制作。但是不知从何处下手。谁给点建议… 查看全部问答> |
|
我仿真了一下图中的电路 波形显示负反馈的正常放大,而正反馈的就一直为高电平为什么啊!按计算的话不是一样么,还是正反馈的算法不一样?求教… 查看全部问答> |
|
请问,现有一个信号的DTFT,如图所示 如何求这个信号的,能量,是能量,不是功率,似乎是用,这个帕斯瓦尔公式,可是不确定,积分只积正负pi以内的部分还是整个域内?还有是否应该除以这个2pi,看到某些地方又没有除2pi,好纠结,非常急,在线等啊 ...… 查看全部问答> |
|
用AVR STUDIO 6.0写程序,出现while(!flag);这样的独立语句时,好像就进不了中断的,定时器计数都是错误的,不知道为什么,哪个大神给解释一下… 查看全部问答> |




