ARM 学习笔记(二) S3C2440 中断配置

来源:互联网 发布:如皋 java培训学校 编辑:程序博客网 时间:2024/04/27 04:02
 

经过几天的努力,到现在总算是有点成就了, 废话少说,上代码:大笑

 

#include <stdlib.h>
#include <string.h>
#include "def.h"
#include "option.h"
#include "2440addr.h"
#include "2440lib.h"
#include "2440slib.h"
#include"mmu.h"

UINT8  x=0;:

void Timer1_Init( void )
{
  rCLKCON=0xfffff0;    //enable pwmtimer clk input
   rTCFG0=0;
   rTCFG0=0x7c;         //PRESCALER value
   rTCFG1=0;
   rTCFG1=0x20;         //divider value
   rTCON=0;             //clear Tcon
   rTCNTB1=0xc350;      //
  rTCMPB1=0;           //
  rTCON|=0x200;        //enable manual update
   rTCON=0x900;
 
}
void Isr_Init(void)
{
 pISR_UNDEF =(unsigned )0;
 pISR_SWI      =(unsigned )0;
 pISR_PABORT =(unsigned )0;
 pISR_DABORT =(unsigned)0;
 rINTMOD  =0x0;
 rINTMSK  =BIT_ALLMSK;
}

static void  __irq Timer1_ISR(void)
{
 

 rSRCPND=rSRCPND;//clear SRCPND bit

 rINTPND=rINTPND;// clear INTPND bit

   rGPBDAT=(1<<(5+x));
   x++;
   if(x==4)
    x=0;  
}

 

void ISR_Init(void)
{
  // 设置中断控制器
 rPRIORITY = 0x00000000;  // 使用默认的固定的优先级
 rINTMOD = 0x00000000;  // 所有中断均为IRQ中断
 pISR_TIMER1= (UINT32) Timer1_ISR;
 rINTMSK &= ~(1<<11);   // 打开TIMER1中断允许
}

int  main (void )
{
 MMU_Init();
 Isr_Init();
 
  ISR_Init();
 
 Timer1_Init();
 rGPBDAT=(1<<5);
 while(1);
 return 0;
}
这是ADS(本打算在IAR下,无奈小弟水平有限,无法把启动代码移植完善,只能在ADS下先用着了尴尬大笑)下,用定时器1 控制开发板上的LED,实现流水灯(1秒)的配置,在RAM 中调试通过。

下面我将单点我在调试中遇到的问题做解答,写出来广大同学少走弯路~~再次声明小弟水平有限,高手勿喷~~谢谢合作!!!

1:中断没有初始化,即:

void Isr_Init(void)//
{
 pISR_UNDEF =(unsigned )0;
 pISR_SWI      =(unsigned )0;
 pISR_PABORT =(unsigned )0;
 pISR_DABORT =(unsigned)0;
 rINTMOD  =0x0;
 rINTMSK  =BIT_ALLMSK;
}

void ISR_Init(void)
{
  // 设置中断控制器
 rPRIORITY = 0x00000000;  // 使用默认的固定的优先级
 rINTMOD = 0x00000000;  // 所有中断均为IRQ中断
 pISR_TIMER1= (UINT32) Timer1_ISR;
 rINTMSK &= ~(1<<11);   // 打开TIMER1中断允许
}

特别是: pISR_TIMER1= (UINT32) Timer1_ISR  这一句如果没有将导致无法进中断,原因后边解释

2: 中断服务函数没有加关键字:__irq 

static void  __irq Timer1_ISR(void)
{
 

 rSRCPND=rSRCPND;//clear SRCPND bit

 rINTPND=rINTPND;// clear INTPND bit

   rGPBDAT=(1<<(5+x));
   x++;
   if(x==4)
    x=0;  
}

若不加 关键字 __irq  将导致中断服务函数无法返回。关键字 __irq  通知编译器本函数是中断服务函数,做好返回的所有寄存器的保存工作,当中断服务函数执行完毕后,恢复中断响应之前的寄存器值。(我从在这耗费了大半天的时间,还好网上有解释得意)   

3:没有清中断源挂起寄存器(SRCPND)、中断挂起寄存器(INTPND)的相应的标志位

 rSRCPND=rSRCPND;//clear SRCPND bit

 rINTPND=rINTPND;// clear INTPND bit

若不加这两句,中断将会响应一次,(这样说不太准确还是看datasheet吧 )

对  SRCPND 的描述 :

In the interrupt service routine for a specific interrupt source, the corresponding bit of the SRCPND register has to becleared to get the interrupt request from the same source correctly. If you return from the ISR without clearing the bit,the interrupt controller operates as if another interrupt request came in from the same source. In other words, if a specific bit of the SRCPND register is set to 1, it is always considered as a valid interrupt request waiting to be serviced.

对  INTPND 的描述:

Like the SRCPND register, this register has to be cleared in the interrupt service routine after clearing the SRCPND register. We can clear a specific bit of the INTPND register by writing a data to this register. It clears only the bit positions of the INTPND register corresponding to those set to one in the data.

不知道上边这几句话,同学们看懂了没,要是没看懂那就…………(有道,谷歌,必应吧               不过这个不是给不过英语四六的找理由哈~~)

二、

下面就ARM的中断系统做一下简单的介绍,对   pISR_TIMER1= (UINT32) Timer1_ISR   的由来,做一下解释~得意

ARM内核有多少个中断引脚??

要是你说有俩,那么恭喜你!!!!答对了。

2440 有多少个中断源 ? 60个!恭喜你,又答对了。

那么这么多中断源,只有俩引脚怎么能响应过来呢,这叫中断引脚复用(这个名词是我自己给它起的~

 

这么多中断,最后全都汇集到IRQ 引脚上了(这里只介绍  IRQ  ,FIQ暂不介绍),那Core怎么分辨出到底是哪个中断源,发来了中断请求呢?

下面请看2440init,s文件;

这里使用了两次查寻的办法,来实现的

我将从Timer1中断请求产生到响应的过程,来描述一下,中断的响应。

(1)当Timer0 产生一个中断请求信号INT_TIMER1  进入ARBITER2 再进入ARBITER0 最后到达Core  ,Core 将跳到 HandlerIRQ   0x18   处执行,

 了解定义:HandlerIRQ HANDLER HandleIRQ

将  以上宏定义带入  宏定义体得到:

 MACRO
$HandlerLabel HANDLER $HandleLabel

HandlerIRQ ;标号
 sub sp,sp,#4    ;(1)减少sp(用于存放转跳地址)
 stmfd sp!,{r0}   ;(2)把工作寄存器压入栈(lr does not push because it return to original address)
 ldr     r0,=$HandleIRQ;将HandleXXX的址址放入r0
 ldr     r0,[r0]    ;把HandleXXX所指向的内容(也就是中断程序的入口)放入r0
 str     r0,[sp,#4]      ;(3)把中断服务程序(ISR)压入栈
 ldmfd   sp!,{r0,pc}     ;(4)用出栈的方式恢复r0的原值和为pc设定新值(也就完成了到ISR的转跳)
 MEND

 

就着图自己琢磨琢磨。这是完成第一次跳转此时跳到  HandleIRQ 处  ;

(2)

HandleIRQ 在文件的最下端  有

 ALIGN

 AREA RamData, DATA, READWRITE

 ^   _ISR_STARTADDRESS  ; _ISR_STARTADDRESS=0x33FF_FF00
HandleReset  #   4
HandleUndef  #   4
HandleSWI  #   4
HandlePabort    #   4
HandleDabort    #   4
HandleReserved  #   4
HandleIRQ  #   4
HandleFIQ  #   4

;Do not use the label 'IntVectorTable',
;The value of IntVectorTable is different with the address you think it may be.
;IntVectorTable
;@0x33FF_FF20
HandleEINT0  #   4
HandleEINT1  #   4
HandleEINT2  #   4
HandleEINT3  #   4
HandleEINT4_7 #   4
HandleEINT8_23 #   4
HandleCAM  #   4  ; Added for 2440.
HandleBATFLT #   4
HandleTICK  #   4
HandleWDT  #   4
HandleTIMER0  #   4
HandleTIMER1  #   4
HandleTIMER2  #   4
HandleTIMER3  #   4
HandleTIMER4  #   4
HandleUART2   #   4

……………………

……………………

我们发现在这里找到 HandleIRQ ,^ 其实就是 MAP ,这段程序的意思是,从 _ISR_STARTADDRESS开始,预留一个变量,每个变量一个标号,预留的空间为 4个字节,也就是 32BIT,其实这里放的是真正的C写的处理函数的地址,说白了,就是函数指针 ~~~

HandleIRQ   是函数指针,那这个指针指向哪里呢?

我们找到这么一段话

; Setup IRQ handler

ldr r0,=HandleIRQ ;This routine is needed

ldr r1,=IsrIRQ ;if there is not 'subs pc,lr,#4' at 0x18, 0x1c

str r1,[r0]

这句话的作用就是将 IsrIRQ 的地址填到 HandleIRQ对应的地址里面

那下面Core 将会去 IsrIRQ 代码段执行 ,我们接着去IsrIRQ  处研究 ;

IsrIRQ
 sub sp,sp,#4        ;给PC寄存器保留 reserved for PC
 stmfd sp!,{r8-r9} ;把r8-r9压入栈

 ldr r9,=INTOFFSET ;把INTOFFSET的地址装入r9  INTOFFSET是一个内部的寄存器,存着中断的偏移
 ldr r9,[r9]   ;I_ISR
 ldr r8,=HandleEINT0 ;这就是我们第二个中断向量表的入口的,先装入r8

add r8,r8,r9,lsl #2  ;地址对齐,因为每个中断向量占4个字节,即isr = IvectTable + Offeset * 4
 ldr r8,[r8]    ;装入中断服务程序的入口
 str r8,[sp,#8]   ;把入口也入栈,

 ldmfd sp!,{r8-r9,pc} 弹出栈,,顺便把r8弹出到PC了,跳转成功!得意
 
 LTORG

 

此时Core 真正跳到中断服务函数了,至此中断两次查表完成,跳转完成··

貌似还忽略了点什么~~,对!!!

那就是 pISR_TIMER1= (UINT32) Timer1_ISR    到现在还没看出有用来 

#define pISR_TIMER1   (*(unsigned *)(_ISR_STARTADDRESS+0x4c))  这个地址,就是  HandleTIMER1 的地址 ,现在明白了没  ?

当然就是HandleEINT0 (基地址)+(#11<<4)  =HandleTIMER1 (地址)

 

哎~~~,好累 ,就先写到这吧  ~~小弟水平有限   ,勿喷,谢谢合作 ~~

可以共同研究 ~~Q99636448~~嘿嘿 大笑

  

                                                                                                                                                                                                                                                                                                                                                                                                                                                  Atlas.dayong

 

原创粉丝点击