S3C6410中断控制,基于OK6410A裸机按键中断程序设计

来源:互联网 发布:乐视员工获刑4年 知乎 编辑:程序博客网 时间:2024/05/22 00:30

近来为了学习Linux嵌入式系统的移植,买了块OK6410A的开发板,当然从裸机程序的开发开始了,然后不可避免遇到了按键中断这样的程序,下面按照思考的过程,写下总结吧!

 

一:首先,弄清楚硬件连接,通过查看原理图,得到了这样的硬件连接

KEYINT1-GPN0-EINT_G0_0

KEYINT2-GPN1-EINT_G0_1

KEYINT3-GPN2-EINT_G0_2

KEYINT4-GPN3-EINT_G0_3

KEYINT5-GPN4-EINT_G0_4

KEYINT6-GPN5-EINT_G0_5,然后就去S3C6410datasheet寻找对应的端口说明吧,一看不知道,看了吓一跳,三星这个英文文档写的,感觉忒不严谨了,有叫“External Interrupt Group 1”的,有叫“Ext. Interrupt Group 8”的,还有“Ext. Interrupt Group”的,其实他们都是并列关系,外部中断的9个Group,你说为啥不统一写成“Ext. Interrupt Group0、Ext. Interrupt Group1”这样呢,非要一会儿缩写一会儿把0都省去了,害得我前后看了几遍GPIO部分。

 

既然端口对应上了外部中断EINT,决定去统一的整理下S3C6410的中断机制。

1、外部中断源控制器EINT,他一共被分为9个组,每组里面对应不同的IO管脚,S3C6410共有127个外部中断,其外接I/O引脚及分组如下:

外部中断组0   EINT_G0  GPN0---GPN15 、GPL8---GPL14、GPM0---GPM4

外部中断组1   EINT_G1  GPA0---GPA7、GPB0---GPB6

外部中断组2   EINT_G2  GPC0---GPC7

外部中断组3   EINT_G3  GPD0---GPD5

外部中断组4   EINT_G4  GPF0---GPF14

外部中断组5   EINT_G5  GPG0---GPG7

外部中断组6   EINT_G6  GPH0---GPH9

外部中断组7   EINT_G7  GPO0---GPO15

外部中断组8   EINT_G8  GPP0---GPP14

外部中断组9   EINT_G9  GPQ0---GPQ9

以上127个引脚每个引脚都可以产生一个外部中断

 

2、ARM的总中断控制器VIC,他由两个VIC组成,联合起来控制了64个中断源,每个控制32个,因此我们发现VIC的控制寄存器都是对应的有VIC0就有VIC1,其中我们找到了与外部中断有关的127个外部中断在VIC里的中断号的对应关系:

NO.      中断源          说明明                            GROUP

0        INT_EINT0       外部中断组0 (EINT_G0)引脚号0-3              VIC0

1        INT_EINT1       外部中断组0 (EINT_G0)引脚号4-11             VIC0

32       INT_EINT2       外部中断组0 (EINT_G0)引脚号12-19            VIC1

33       INT_EINT3       外部中断组0 (EINT_G0)引脚号20-27            VIC1

53       INT_EINT4       外部中断组1-9 (EINT_G1~9)                    VIC1

我们发现属于外部中断组0的27个中断占用了VIC里的4个中断号,外部中断组1-9只占用了1个中断号,世界就是这么的不公平,努力吧!

 

3、S3C6410的中断流程,说到这里,大家是不是觉得有点乱(如果使用过STM32应该不会乱,因为STM32的中断也是两级控制的),我们总结下具体的中断流程:

外设(GPIO)——》EINT——》VIC——?,因此对应的我们编程序也就是

外设配置——》EINT配置——VIC配置——?,这是我们现在所能想到的,大家也觉得分析的不错吧,可惜错误也再此埋下了伏笔,即是问号处,


二: 前面大概讲了一下外部中断的流程,现在我就开始按照此流程,结合具体的硬件进行整理和编程了。下面讲到具体的寄存器都按照OK6410开发板对应的GPN讲解。

 

1GPIO的配置

相信你已经开始写中断程序了,基础的IO控制LED的程序肯定已经写过了,那一定知道控制GPIO一般就如下几个寄存器:

GPNCON——端口控制寄存器、可读可写

GPNDAT——端口数据寄存器、可读可写

GPNPUD——端口上下拉寄存器、可读可写,对于按键中断,显然我们只需要用到GPNCON,将端口设置为中断模式即可,按照下图,将对应的位设置为10即可。

rGPNCON &= ~((0x03<<0)|(0x03<<2)|(0x03<<4)|(0x03<<6)|(0x03<<8)|(0x03<<10));//把两位都变为00,也可以写成~(0xfff<<0)

rGPNCON |= ((0x02<<0)|(0x02<<2)|(0x02<<4)|(0x02<<6)|(0x02<<8)|(0x02<<10));//把前一位变为1,也可写成0xaaa<<0     

此处为了更清楚的表明设置的过程,设置的稍有复杂,大家可以直接简化为注释后面的,同时为了不对其他端口造成影响,严格采用了对应的与或操作。

 

2EINT配置,对应前面描述的中断知识,本按键GPN0~5只涉及到了GROUP0的中断EINTEINT_G0,具体说是EINT_G0_0~5

关于EINT的配置,我们先总结一下可能涉及到的寄存器:

总结下来就是四类,EINT控制寄存器,滤波控制寄存器,中断屏蔽寄存器,中断挂载寄存器,当然还有关于优先级等寄存器,如PRIORTY,SERVICE,SERVICEPEND这些,比较高级的功能,我也没有深入,此处暂不表。

此处说一下常用的这三类,(1EINT控制寄存器,用来控制外部中断的触发方式,比如此处可以设定为低电平触发。

//设置外部中断EINT触发方式低电平触发为x000,最高位忽略,默认为x000,两个共用一个

rEINT0CON0 &= ~((0x07<<0)|(0x07<<4)|(0x07<<8));//把三位都变为0,也可以写为~(0x777<<0)

2)中断屏蔽寄存器EIN0MASK,可读可写,写1屏蔽中断,写0使能中断。此时,我们首先肯定要使能按键中断口。

//设置中断使能,即将中断屏蔽寄存器置0,

rEINT0MASK &= ~((0x01<<0)|(0x01<<1)|(0x01<<2)|(0x01<<3)|(0x01<<4)|(0x01<<5));//把一位变为0,也可以写成~(0x3f<<0)

3)中断挂载寄存器EINT0PEND,可读可写,读1表示发生中断,读0表示未发生中断,写1表示清除外部中断。

//清楚外部中断挂载,即外部中断挂载寄存器写1,清楚中断

rEINT0PEND |= ((0x01<<0)|(0x01<<1)|(0x01<<2)|(0x01<<3)|(0x01<<4)|(0x01<<5));//把一位变为1,也可以写成(0x3f<<0)


三:

VIC的配置,对应前面讲的对应前面描述的中断知识,本按键GPN0~5只涉及到了GROUP0的中断EINTEINT_G0,具体说是EINT_G0_0~5。再次对应到VIC,我们看到其中GPN0~3对应了EINT_G0_0~3,对应了INT_EINT0GPN4~5对应了EINT_G0_4~5,对应了INT_EINT1,这两者都是在VIC0中,分属NO0NO1

然后关于VIC我们总结下相应的寄存器:此处仅以VIC0为例,选出了常用的一些寄存器,其他类似于中断优先级,软中断等等,还没有研究,需要共同学习。

1VIC0INTSELECT——中断选择寄存器,可读可写,0-选择IRQ1-选择FIQFIQ更快,一般选IRQ32位分别对应每一个中断源;

2VIC0INTENABLEVIC0INTENCLEAR,这两者是一对的,其中VIC0INTENABLE——系统中断使能寄存器,可读可写,0-中断禁止,1-中断使能,一般只能用来使能中断,不能用来写0禁止中断,禁止中断使用VIC0INTENCLEAR——系统中断清除,可写,写0无效,写1-禁止中断,大家注意配合使用,32位分别对应每一个中断源;

3VIC0VECTADDR[0~31] ——矢量地址寄存器,即对应的中断服务程序的入口地址,一共32个地址,对应VIC032个中断源。可读可写;

4VIC0ADDRESS——又一个矢量地址寄存器,糊涂了吧,记住它的功能就行,通过向其写入任意值,就可以清除中断服务标志,类似于外部中断EINT中的EINT0PEND了,我们可以通过它在中断服务程序中清除系统中断标志,32位分别对应每一个中断源;

 

介绍完了这些VIC对应的寄存器,现在开始说说其配置的流程:

(1)       首先肯定是需要设定中断的类型IRQ还是FIQ,配置之前呢,先把对应的中断关了,因此,先需要禁止对应的系统中断。

//关闭对应的中断,对应位写1关闭系统中断,只能写32位,同rVIC1INTENCLEAR一起与rVIC0INTENABLE/rVIC1INTENABLE配套

rVIC0INTENCLEAR |= (0x01<<0|(0x01<<1));//外部中断0_0~5属于系统中断INT_EINT0/INT_EINT1

2)那其次就是上面说的设定中断的类型IRQ还是FIQ了。

//设置系统中断类型,对应位写0-IRQ,1-FIQ,只能写32位,同rVIC1INTSELECT一起

rVIC0INTSELECT &= ~((0x01<<0)|(0x01<<1));//外部中断0_0~5属于系统中断INT_EINT0/INT_EINT1

3)然后呢清除系统中断标志

/清除系统中断,对应位写0或者1都行,只能写32位,同rVIC1ADDRESS一起

rVIC0ADDRESS &= ~((0x01<<0)|(0x01<<1));//外部中断0_0~5属于系统中断INT_EINT0/INT_EINT1

4)设定中断服务程序的入口地址

//写中断处理程序地址,rVIC0VECTADDR

VIC0VECTADDR[0] = (unsigned)Key1_handler;//unsigned说明是32位地址

VIC0VECTADDR[1] = (unsigned)Key2_handler;//unsigned说明是32位地址,这里需要说明,这边是3232位的数组对应32个中断源的处理地址,因此宏定义的时候需要注意,此处宏定义跟其他寄存器定义有区别。

#define VIC0VECTADDR             (( unsigned *)(0x71200100))

#define VIC1VECTADDR                    (( unsigned *)(0x71300100))

5)使能系统中断

//使能系统中断,对应位写1使能系统中断,只能写32位,同rVIC1INTENABLE一起与rVIC0INTENCLEAR/rVIC1INTENCLEAR配套

rVIC0INTENABLE |= (0x01<<0|(0x01<<1));//外部中断0_0~5属于系统中断INT_EINT0/INT_EINT1

GPIO的配置

这样一个简单的系统中断VIC配置就算完成了。

 

4、接下来就是中断服务程序了,这个大家都弄腻了,需要注意的就是清除中断标志,从上面可以看出,这里需要清除两个中断标志,分别是外部中断EINT和系统中断VIC的标志,例如rVIC0ADDRESS &= ~(0x01<<0);//清除系统中断INT_EINT0

以及rEINT0PEND |= (0x01<<0);//清除外部中断0_0

例外可以通过读rEINT0PEND的某一位,知道具体是外部中断EINT_G0的哪一个口发生中断。

 

大家是不是觉得这样就OK了呢,我也是这么想的,然后就下载程序进行了在线调试,可惜啥效果没有,然后又认真的把每一个寄存器又都检查了一遍,还是没有发现错误,疑惑不解啊。这就又回到了一开始埋下的伏笔那, 

四:

经过前面的准备,0K6410的按键中断基本搞定了,但是还有一个地方被我们大家遗漏了,于是我跟众多网友一样,停滞在这里,调不通按键中断了,没办法啊,中断就是不响应。

 

于是又回到了一开始埋下的伏笔那,S3C6410的中断响应流程那,外设(GPIO)——》EINT——》VIC——?,因此对应的我们编程序也就是外设配置——EINT配置——VIC配置——?,这个问号处,是被我们忽视的地方。(此处各种上网查找,也有好多网友给出了正确答案,这里不一一致谢了哈,反正是各种实验哦)

 

下面是S3C6410应用笔记(apnv1.0)中断部分的截图,通过图我们发现,第一部分,我们没有做啊,即使能VIC接口(enable vic port)。当然还有另外一个方法,不太常用,一般都用这个调用VIC PORT

按照笔记,使能VIC PORT,这里给出了一段汇编代码,尼玛,汇编不太会啊,这个放在哪儿呢,如果放在C程序中,需要内嵌汇编,使用asm又报错,没能解决,参考网上,有人放在了启动代码中,果断复制到启动代码中。

;------------------------------------

;     Enable VIC Port

;------------------------------------

             mrc p15,0,r0,c1,c0,0

                   orr r0,r0,#(1<<24)

                   mcr p15,0,r0,c1,c0,0

 

到了这里,好多网友都运行成功了,可是我这里还是没有运行成功,这又让我很郁闷,最终在网上众多博客中,找到了一篇http://blog.csdn.net/tankai19880619/article/details/8310050

,他里面另外还有一段汇编,使能IRQ,我把这段汇编copy到启动代码中,经过尝试,成功了,哈哈,虽然他博客中写的他自己没有调试成功。这个哥们的博客http://blog.csdn.net/yin138/article/details/6738917中也有类似的这段代码。

;------------------------------------

;     Enable IRQ

;------------------------------------               

                   mrs r0,cpsr

                bic r0,r0,#0x80

        msr cpsr_c,r0

就这样,最终按键中断的功能得以实现,真是一波三折啊。最终汇总一下整个流程:

外设(GPIO)——》EINT——》VIC——协处理器,因此对应的我们编程流程也就是

外设配置——EINT配置——VIC配置——使能VIC PORT和使能IRQ



0 0
原创粉丝点击