mini2440+jlink+mkd 裸机按键中断调试心得体会(2013.11.17已更新)

来源:互联网 发布:手机续航测试软件 编辑:程序博客网 时间:2024/06/05 18:58

开发板:友善之臂mini2440,仿真器:jlink v8,开发环境:RealView mdk 4.54

需要阅读的文档:S3C2440A_UserManual,mini2440开发手册,其他

实验目标:按下开发板上的key1,触发外部中断EINT8,开发板进入中断程序运行点亮或灭掉LED1

分析:

为了方便理解,我按照信号的走向,分为几个环节,逐个说明。

环节1.先说说,按下key1是如何触发外部中断信号。阅读mini2440的开发手册后发现key1是和s3c2440芯片上的GPG0管脚相连,这个IO口除了能作输入输出用,还可以功能复用为EINT8,即2440众多的外部中断源之一。也就是说,我们把这个GPG0的功能配置为EINT8后(相应的寄存器为GPGCON),它就把key1的信号当做中断信号了。

key1按下时是低电平,那这个时候就有一个问题了,cpu怎么知道你是按键抬起来表示想触发中断,还是按下去时想触发中断,这里就要配置一个叫做EXTINTn(具体可参考S3C2440A_UserManual)的寄存器把这件事确定下来,开发板上电后这个寄存器默认EINT8是低电平触发。

这里还要介绍两个寄存器EINTPEND和EINTMASK,EINTPEND是用来显示有哪个外部中断源触发了(比如当你按下按键后,发现EINTPEND没变化,那你就得琢磨是不是你的按键坏了,还是刚才那个EXTINTn的寄存器没配置好),EINTMASK是来决定中断信号是否能进入中断控制器的(说白了,就是你这个中断信号能不能进入下一环节)。

环节1总结:涉及的寄存器:GPG0,EXTINTn,EINTPEND,EINTMASK

由于有些寄存器上电后的默认配置就能满足我们的需要,所以这一环节只要配置GPG0,EINTMASK

环节1完成的任务:EIN8成功触发,进入中断控制器。


环节2:

图1

我们看图1,中断信号从左面一直流向右面,这其中,中断信号每向右走一步都会涉及到一些寄存器的配置,我们一一分析下。

接环节1,图中红字外部中断信号EINT8出现在Request sources的位置,成功进入了中断控制器里,可能有人会问,为什么要有中断控制器?这个中断控制器是干什么的?因为,CPU在同一时刻只能处理一个中断信号,而在同一时刻可能有很多中断信号源被触发,所以得有个“机构”帮CPU挑一个中断信号处理,好让cpu去处理别的事情。这就是中断控制器的存在意义和任务了。

我们看图1,EINT8属于下面那个中断源,它进入中断控制器后马上进入SRCPND这个寄存器,这个寄存器可以告诉我们目前都有哪些中断源请求中断处理了。

接下来,我们需要配置两个寄存器:INTMOD和INTMASK,INTMOD用来选择中断信号是进入IRQ模式还是FIQ模式,当中断信号选择IRQ模式时,信号会进入MASK环节,当选择FIQ模式时,信号直接流向右下端的FIQ,让CPU进入FIQ模式,跳转到FIQ中断程序。

继续把中断信号选择IRQ模式后要走的环节说完,寄存器INTMASK决定中断信号是否能进入Priority(优先级判断)环节,前面提到过,同一时刻可能会有很多歌中断信号触发进入中断控制器,因此我们需要一个机制判断哪一个信号最终能获得CPU的处理,那么这个机制也是通过配置一个叫PRIORITY的寄存器完成的。

我们看到图中还有一个叫INTPND的寄存器,它显示了谁最终获得了让CPU处理它的权利。

环节2总结:涉及的寄存器:SRCPND,INTMOD,INTMASK,,PRIORITY,INTPND

实际需要的配置的寄存器:无。都默认配置

环节2完成的任务:让CPU进入IRQ模式或者FIQ模式

环节3:此时,CPU已经进入IRQ模式或者FIQ模式了。pc会指向位于地址0x00000000的异常向量表的0x00000018(这里注意必须用全速模式才能让cpu进入IRQ模式,pc跳转到0x00000000,单步调试cpu不会进入IRQ模式,pc也不会跳转到0x00000000,),接着进入中断程序(这里涉及怎么用代码实现跳转,后面还是把代码放出来吧)。

进到中断程序后,要做如下几件事:1.点亮或者关灭LED1,2.清中断请求(这里涉及3个寄存器,按顺序依次将EINTPEND,SRCPND,INTPND清零,清零的方式是向EINT8对应的那位写1)3.防抖动:防抖动主要是实现按一次key1,只触发一次中断请求。方法是先检测按键是不是回到高电平了,再延时一定时间,再检测是不是高电平,如果还是高电平,那我们99%可以确定按键已经抬起了,把这段代码循环执行,就可以实现按一次key1,只触发一次中断请求的目标了。4.把lr的值给pc(回到执行中断程序之前程序运行的地方继续执行,这里注意lr的值是cpu在进入IRQ模式前自动把当前的pc值存入lr里的,实际上根据不同的模式,你还要在lr上加一个偏移量,我理解为的是为了不漏掉执行进入IRQ模式前的指令,详情看芯片手册)

大总结:

1.还是贴出代码了,有些细节用文字说得不够明白,直接贴代码研究比较方便

2.如果调试程序的话,程序运行在0x30000000处,异常向量表在0x00000000,所以你得在程序里写一个中断向量表,然后copy到0x00000000处。而且注意只能给PC一个绝对地址。不能是相对地址,因为你的指令已经经过编译器了,指令里的偏移量肯定是不适合0x00000000处的异常向量表的。

3.还有一点是别忘了在CPSR里把IRQ或者FIQ的使能位清零,这样CPU才能进入相应的工作模式,

4.学习arm9也近两个星期了,跟大家分享下心得:一个大目标要分解成很多的小目标,一个目标,一个目标的去完成,这样思路才容易清晰,包括写程序是这样,调试也是这样,这是最基本的学习思路了

  5.ARM官网的文档,s3c2440芯片和mini2440的手册都很重要,我基本上就是看这些学习和解决问题,当然也要善用百度,网上的文章,主要是看个知识框架,对某个知识点有一个宏观的认识,细节的东西还要自己去啃文档,文档才是最全面的。多动手,多实践

6.代码里防抖动的延时时间太短,如果中断请求为低电平触发,效果不是很好,所以采用下降沿触发了,如果低电平触发,要把延时时间弄得长一点

代码:mini2440+jlink v8+mkd4.54调试通过

AREA KEY,CODE,READONLYENTRYexception_vectorb startnopnopnopnopnopb irqnopirqmov r0,#0x30000000add r0,r0,#0x2cmov pc,r0eint5;进入调试模式,查看该地址是0x3000002cmov r0,#0x56000000;reverse gpb5add r0,r0,#0x14ldr r1,[r0]eor r1,r1,#0x20mov r0,#0x56000000;add r0,r0,#0x14str r1,[r0]1mov r0,#0x56000000;防抖动add r0,r0,#0x64ldr r1,[r0]mov r0,#0x1and r1,r1,r0cmp r1,#0x1bne %b1nopnopnopmov r0,#0x56000000;add r0,r0,#0x64ldr r1,[r0]mov r0,#0x1and r1,r1,r0cmp r1,#0x1bne %b1mov r0,#0x56000000;clear eint8-23 request in EINTPND registeradd r0,r0,#0xa8mov r1,#0x1<<8str r1,[r0]mov r0,#0x4a000000;clear eint8-23 request in SRCPND registeradd r0,r0,#0x0mov r1,#0x20str r1,[r0]mov r0,#0x4a000000;clear eint8-23 request in INTPND registeradd r0,r0,#0x10mov r1,#0x20str r1,[r0]subs pc,r14,#4startmov r0,#0x56000000;set GPG0 as EINT8add r0,r0,#0x60mov r1,#0x2str r1,[r0]mov r0,#0x56000000;set EINT8 falling edge triggeredadd r0,r0,#0x8cmov r1,#0x4str r1,[r0]mov r0,#0x56000000;clear EINT8 mask in EINTMASK registeradd r0,r0,#0xa4mov r1,#0xfffffeffstr r1,[r0]mov r0,#0x4a000000;clear EINT8 mask in INTMASK registeradd r0,r0,#0x8mov r1,#0xffffffdfstr r1,[r0]mov r0,#0x56000000;set gpb5 as outadd r0,r0,#0x10mov r1,#0x400str r1,[r0]mov r0,#0x56000000;light led1 add r0,r0,#0x14mov r1,#0x0str r1,[r0]mrs r1,cpsr;enable IRQ in cpsrbic r1,r1,#0x80msr cpsr_c,r1init_excpvct1ldr r0,=exception_vector;copy the exception_vector to 0x00000000ldr r1,=0x00000000add r2,r0,#48             ;这里的数字要大于44,是因为要把异常向量表和下面IRQ那三条一共11条指令都拷过去0  ;由于r3-r6一共4个寄存器,所以还得是16的倍数,因此选48ldmia r0!,{r3-r6}stmia r1!,{r3-r6}cmp r0,r2bne %b0lb lend