关于ARM中断实现与理

来源:互联网 发布:工程计量软件叫金路 编辑:程序博客网 时间:2024/05/19 00:42

 

       这个过程有助于ARM中断的理解,以及锻炼我们查手册的能力,很好的例子。因为在刚接触ARM的时候,很多的东西都是围绕在我们的寄存器的操作上,这个寄存器的数量在我们ARM920T这块芯片上,就让很多人迷茫在寄存器里的大海里了;那么更加不用说我们更高级一点儿的Cortex A8平台上了,那将会有更多的寄存器需要我们去操作,所以我们必须掌握好一种学习ARM的方法。很多人对这些外设的操作,因为难度很大的原因,都迈不出第一步,那就是“有目的的去查手册”,尤其是看到纵横交错的电路图时,很多初学者都望而生畏的翻片儿了,理由是,这个偏硬件太多,我感兴趣的只是U-boot和Linux的移植,以及驱动的相关。这也不为过,因为初学者总是被这些热点的东西所吸引,站在兴趣是我们学习知识的最有劲的动力的角度上,一点儿也不为过。但,在我们的驱动学习过程中,还是针对于这些常用的外设展开的

我门的步骤是:

(1)初始化我们的SARM用于中断程序到时候跳转过去,我们的这个程序是在NorFlash上运行的。但是中断程序是在SRAM中加载到我们的MCU去执行的。

(2)我们这里需要两个手册,一个是S3C2410这个datasheet,以及我们的原理图,可以在网上下载!s3c2410的核心原理图和手册。

(3)我们这个实验的主要东西是中断,所以,首先我打开S3C2410的手册【um_s3c2410a_manual_r10.pdf】,我们在书签里面找到”INTERRUPT CONTROLLER“项。

打开后这个图首先引入眼帘,大概意思是:中断控制器S3C2410A在接收来自56个中断源的Request时,我们的中断控制器的功能流程图就是上面这个图。这些中断源来自于,内部外设(是指相对于Core,如DMA控制器,采用通用异步收发机,IIC等等。  

当从内部,以及从引脚传来的外部中断请求。ARM920T Core会在我们的中断仲裁程序(即通过优先级或者是条件来选择谁运行)跑起来后,通过我们请求的到底是FIQ,还是IRQ来选择不同的方式相应中断。(你可能要问ARM有7中断模式,为什么只响应这两种中断呢?因为在我们的中断分类中,只有FIQ和IRQ是从外部来驱动我们的中断响应的,其他的那些使我们的Core在和内部实现好的,不能够直接被外界驱动)。响应中断的仲裁程序,依赖于硬件优先逻辑;结果是写入待定寄存器(pending  register),这个寄存器,有助于用户知道是由那个中断源,产生的中断。

因为我们的pending  register(在我们的程序中的表示方式是“EINTPEND”),这个寄存器,你可以查手册找到如下图的内容

我们需要注意的是这个EINTPEND寄存器的【3:0】0到3位是无效的,FIQ只有一个,但是IRQ却有多个,而这多个中断IRQ请求都有这个寄存器来存储,我们用它的相应的位来区别出到底是那个中断源发来的中断请求。

(4)接下来,我们选择我们的中断程序到底用几号外部中断。

比如我们这里要实现的是一个键盘中断响应的功能模块:

a.查看我们的外设的原理图【FS2410-CORE-V5.0.pdf】,找到如下的图片,这个过程最好自己找找,多动动手,你就会慢慢的对手册熟悉起来。

b.注意我们图的左边,共用到了四个外部中断EINT0、EINT2、EINT11、EINT19,我们的程序的流程设计也是来自于我们的硬件的结构,及我们看到的原理图。

c.继续查我们的手册,不过内容分别是这四个外部中断,我们拿EINT0来举例:

在PDF阅读器里面,使用快捷键Ctrl + F ,输入"EINT0",然后一直查找到如下这里:


在最末行,我们看到EINT0这个外部中断是通过我们GPF寄存器的0号引脚实现的。所以很自然的想到操作GPFCON这个寄存器来实现我们的0号外部中断(EINT0)

在PDF阅读器里面,使用快捷键Ctrl + F ,输入"GPFCON",然后一直查找到如下这里:


查到这里,我们看见:当GPF的[0:1]号位为"10"的时候,就能表示0号外部中断。

例: GPFCON=  (GPFCON& (~(0x3<<0))) | (0x2) 这样就表示了EINT0

      GPFCON = (GPECON &( ~(0x3<<12))) + (0x1<<12);  这表示的是   EINT6 

(5)写到这里我们中断基本上有些眉目了,接下来就是我们来按顺序清除我们的断点标志,请把重点放在这个顺序两个字上,这是因为如果你用的是三星的S3C2410的话,那么板子的一个特性(相对于ARM公司指定的统一标准之外,半导体厂家自己在遵守这一标准的前提下,对芯片加上一些自己的特色)。介于S3C2410的断点标志要顺序删除的特性,所以我们这里在收尾工作的时候一定要细心。

下面是核心部分代码:

//设置中断程序的入口地址

#define pISR_EINT0        (*(unsigned *)(_ISR_STARTADDRESS+0x20)) 
#define pISR_EINT8_23     (*(unsigned *)(_ISR_STARTADDRESS+0x34))

#define pISR_EINT2        (*(unsigned *)(_ISR_STARTADDRESS+0x28))

//清楚中断位

#define Clear1Pending(bit)  {SRCPND = bit; INTPND = INTPND;} // precent write wrong data

//设置时钟频率

#define FCLK 202800000
#define HCLK (202800000/2)
#define PCLK (202800000/4)

//中断源
#define UART0 0x0 // UART symbol
#define UART1 0x1
#define UART2 0xBB
//***************************************

void uart_init(int nMainClk, int nBaud, int nChannel)
{
//    int i;
    
    if(nMainClk == 0)
    nMainClk    = PCLK;
    
    switch (nChannel)
    {
    case UART0: 
UFCON0 = 0x0;   //UART channel 0 FIFO control register, FIFO disable
UMCON0 = 0x0;   //UART chaneel 0 MODEM control register, AFC disable
ULCON0 = 0x3;   //Line control register : Normal,No parity,1 stop,8 bits
// [10]       [9]     [8]     [7]          [6]      [5]        [4]         [3:2]          [1:0]
// Clock Sel, Tx Int, Rx Int, Rx Time Out, Rx err,  Loop-back, Send break, Transmit Mode, Receive Mode
// 0          1       0,      0            1        0          0,          01             01
// PCLK       Level   Pulse   Disable      Generate Normal     Normal      Interrupt or Polling
UCON0  = 0x245;// Control register
// rUBRDIV0=( (int)(nMainClk/16./nBaud) -1 );// Baud rate divisior register 0
UBRDIV0=( (int)(nMainClk/16./nBaud+0.5) -1 );// Baud rate divisior register 0    
break;

case UART1: 
UFCON1 = 0x0;   //UART channel 1 FIFO control register, FIFO disable
UMCON1 = 0x0;   //UART chaneel 1 MODEM control register, AFC disable
ULCON1 = 0x3;
UCON1  = 0x245;
UBRDIV1=( (int)(nMainClk/16./nBaud) -1 );
break;
default:
break;
}

}

void uart_sendbyte(int nData)
{
    UTXH0 = nData;
            while(!(UTRSTAT0 & 0x2));
 }

//*************************************

*********************************************************************************************/
void uart_sendstring(char *pString)
{

    while(*pString != '\0')
        uart_sendbyte(*pString++);
}
void uart_printf(char *fmt)
{
    uart_sendstring(fmt);
}
*********************************************************************************************/

//EINT0中断处理函数

void  __irq int0_int(void)
{
    uart_printf(" EINT0 interrupt occurred.\n");
    Clear1Pending(0x1);
}
*********************************************************************************************/

//EINT11和19中断处理函数
void  __irq int11_int(void)
{
if(EINTPEND & (1<<11))
{
 EINTPEND=(1<<11);
   uart_printf(" EINT11 interrupt occurred.\n");
   Clear1Pending(0x1<<5);
}
    else //if(EINTPEND & 1<<19)
{
 EINTPEND=(1<<19);
   uart_printf(" EINT19 interrupt occurred.\n");
   Clear1Pending(0x1<<5);
 //EINTPEND=(1<<19);
}
}
*********************************************************************************************/

//EINT2中断处理函数
void  __irq int2_int(void)
{

  uart_printf(" EINT2 interrupt occurred.\n");
  Clear1Pending(0x1<<2);
}
*********************************************************************************************/
void int_init(void)
{
    SRCPND = SRCPND;                 // clear all interrupt;清零SRCPEN,用以接收下一个同类型的IRQ
    INTPND = INTPND;                 // clear all interrupt;清零INTPND,用以接收下一个同类型的IRQ
    
GPFCON=(GPFCON & ~(3<<0))|(0x2<<0) ;// PF0= EINT0
GPGCON=(GPGCON & ~(3<<6))|(0x2<<6) ;// PG3= EINT11
GPFCON=(GPFCON & ~(3<<4))|(0X2<<4);//PF2 = EINT2
GPGCON=(GPGCON & ~(3<<22))|(0X2<<22);//PG11 = EINT19


//相应的中断处理函数 
pISR_EINT0 = (unsigned int)int0_int;//isrEINT0;
pISR_EINT8_23 = (unsigned int)int11_int;                //isrEINT11_19;
pISR_EINT2  =  (unsigned int)int2_int;//isrEINT2

GPECON=(GPECON&(~(0x3<<22)))+(0x1<<22);//KSCAN0 = 0
// GPEDAT=(GPEDAT&~(1<<11));
GPECON=(GPECON&(~(0X3<<26)))|(0X1<<26);                 //KSCAN2 = 0
GPEDAT=(GPEDAT&~((1<<13)|(1<<11)));
GPGCON=(GPGCON&(~(0X3<<12)))+(0X1<<12);//KSCAN1 = 0
GPGDAT=(GPGDAT&~(1<<6));
GPGCON=(GPGCON&(~(0X3<<4)))+(0X1<<4);//KSCIN3 = 0
GPGDAT=(GPGDAT&~((1<<2)));

//使eintpend清零,接收下一外部中断
EINTPEND = 0xffffff;
// SRCPND = (0x1) | (0x1<<5);//to clear the previous pending states
// INTPND = (0x1) | (0x1<<5);

//设置外部中断触发方式:01x----下降沿触发  
EXTINT0 = (EXTINT0 & ~(7<<0))  | (0x2<<0);                     //EINT0=falling edge triggered
EXTINT0 = (EXTINT0 & ~(7<<8))  | (0x2<<8);
EXTINT1 = (EXTINT1 & ~(7<<12)) | (0x2<<12); //EINT11=falling edge triggered
EXTINT2 = (EXTINT2 & ~(7<<12)) | (0x2<<12);

//设置外部中断屏蔽为,0为使能,1为屏蔽
 //打开0,2,11,19号外部中断
EINTMASK &= ~(  (1<<11) | (1<<19)  );

//设置总的中断屏蔽  
 //打开EINT0,ENT2,EINT8_23
INTMSK   &= ~((0x1)|(1<<2)|(0x1<<5));

 

//消抖EINT19
 EXTINT2 &= 1<<15;
 EINTFLT2 = (0x7f << 24);
}
*********************************************************************************************/
void int_test(void)
{
int_init();
uart_printf("\n External Interrupt Test Example\n");
}
/**********************************************************************************************/
int main()
{
    WTCON = 0;//关闭看门狗
    CLKDIVN = (1<<1) | 1;   //设置  1:2:4
    MPLLCON = (0xa1<<12) | (0x3<<4) | 0x1;  // Fin=12MHz FCLK=202.8MHz
    //=== PORT H GROUP
  //Ports  : GPH10 GPH9     GPH8   GPH7  GPH6  GPH5 GPH4 GPH3 GPH2 GPH1  GPH0 
  //Signal : GPH10  CLKOUT0 SD_WP  CTS1  RTS1  RXD1 TXD1 RXD0 TXD0 nRTS0 nCTS0
    //Setting: Output CLKOUT0 GPH8   nCTS1 nRTS1 RXD1 TXD1 RXD0 TXD0 nRTS0 nCTS0
    //Binary : 10,    10      10,    11    11,   10   10,  10   10,  10    10
    GPHCON = 0x2afaaa;
    GPHUP  = 0x7ff;    // The pull up function is disabled GPH[10:0]
    uart_init(PCLK, 115200, UART0);
    uart_printf ("boot success...");
    int_test();
  while(1);
}


原创粉丝点击