追风者

ARM2200下的中断编程

0
阅读(2219)

 

最近一直在和ARM2200打交道,总结了下在ARM zlg模版中如和编写中断的方法(涉及了向量中断,非向量中断和外部中断的编写方法)

本人初学,以下为本人观点,若有错误,请与我联系交流

一.         前言

中断的基本概念:

1.     在ARM中最多有32个中断请求

2.     16个向量IRQ中断(16个向量中断的VIC中断号已经有系统定义好了。在p208中可查看)

(16个向量中断有16个优先级,可动态分配给中断请求)

3.     可产生软件中断。

4.     中断的优先级资源:中断的优先级资源就是CPU的中断系统。以ARM7体系的CPU为例,最多可以有32个中断资源。对于每个具体的中断源可以将其设定为FIQ,使其具有最高优先级,但FIQ       最好是分配给唯一的中断源,否则就失去意义;也可以设定为向量IRQ,使其具有中等优先级,但向量IRQ的总数不能超过16个,这些中断源优先级的高低按向量编号从0(最高)到15(最低)排序;如果中断源的个数超过17个,则剩余的中断源只能设定为非向量IRQ,其优先级最低。操作系统本身必须使用一个定时器中断源来作为系统节拍中断,它是操作系统工作的基础。

二VIC向量中断控制器

1.     向量中断控制器(VIC)具有32个中断请求输入

a.     可以将其分为3类:

FIQ,向量IRQ中断和非向量IRQ.

b.     快速中断请求(FIQ)要求具有最高优先级。当如果只有一个中断被分配为FIQ时,可现实最短的FIQ等待时间,因为FIQ服务程序只要简单地启动对该中断处理就可以了。

c.      向量IRQ中断具有中等优先级。该优先级可分配32个请求中的16个。32个请求中的任意一个都可以分配到16个向量IRQslot中的任意一个,其中slot()具有最高优先级,而slot15则为最低优先级。

d.     非向量IRQ中断的优先级最低。

2在编写中断程序时最常用的寄存器

a.     中断使能寄存器(VICIntEnable)

(1) VICIntEnable寄存器有32为:从0~31给每一位写1表示时该为对应的中断时能,写入0表示禁止该位的中断。(每一位对应的中断和VIC通道号对应。

Eg:VICIntEnable=1<<6;表示使UART0能中断,因为UART0对应的中断号即为6.

b.     中断选择寄存器VICIntSelect

(1) VICIntSelect:该寄存器有32位(0~31)将32个中断请求分别分配为FIQ或IRQ ,

(2) 给对应位写入1表示给对应的中断请求分配为FIQ

(3) 给对应位写入0表示给对应的中断请求分配为IRQ

C.向量控制寄存器0~15(VICVectCntl0~15)

 (1)如果给一个中断指定的向量控制寄存器为VICVectl0则表示该中断具有最高中断优先级。反之,如果给一个中断指定的向量控制寄存器为VICVectl15则表示该中断具有最低优先级。

(2)VICVectCntlx(x指0~15)该寄存器为6位。

   0~4:用来指定中断编号

   5:为1表示向量使能

Eg;VICVectCntl0=0x20|6(表示给UART0分配向量控制寄存器,且它的优先级是最高的(0表示最高优先级)

D.向量地址寄存器(VICVectAddrx)

(1)当发生一个IRQ中断时,VIC会将对应的IRQ服务程序地址存入该寄存器,IRQ中断入口处的程序可读寄存器并跳转到读出的地址,执行相应的中断服务程序

(注:该寄存器应该在ISR快结束时执行一次些操作(写入的值一般为0)以遍更新优先级硬件。)

(2)在发生中断时,给中断分配中断地址时应该和给该中断分配的中断控制寄存器的号一致

Eg: VICVectCntl0=0x20|6;

       VICVectAddr0=(uint32)UART0_IRQ(自己编写的终端函数的地址)

注:在编写向量中断程序时,必须对他进行初始化。一般的程序过程是:首先:用VICIntSelect寄存器对该中断进行选择时IRQ中断还是FIQ中断。

       其次:用VICVectCntlx给该中断分配向量终端控制寄存器(其中x的值越小,中断优先级越高。

   再次:用VICVectAddrx给该中断分配中断地址:

   最后:用VICIntEnable使该中断使能:

程序事例:

VICIntSelect = 0x00000000;      // 设置所有中断为IRQ中断

VICVectCntl0 = 0x26; // UART0中断分配到IRQ slot 0,即优先级最高

VICVectAddr0 = (int)IRQ_UART0;            // 设置UART0向量地址

VICIntEnable = 0x00000040;                // 使能UART0中断

三非向量中断:

1.     常用寄存器:

a中断使能寄存器(VICIntEnable)

VICIntEnable寄存器有32为:从0~31给每一位写1表示时该为对应的中断时能,写入0表示禁止该位的中断。(每一位对应的中断和VIC通道号对应。

Eg:VICIntEnable=1<<6;表示使UART0能中断,因为UART0对应的中断号即为6.

b中断选择寄存器VICIntSelect

(1) VICIntSelect:该寄存器有32位(0~31)将32个中断请求分别分配为FIQ或IRQ ,

(2)给对应位写入1表示给对应的中断请求分配为FIQ

(3)给对应位写入0表示给对应的中断请求分配为IRQ

注:以上和向量中断的用法一致,一下是不同点

c.      默认向量地址寄存器VICDefVectAddr

该寄存器保存了非向量IRQ中断服务程序IRQ的地址

注:在编写非向量中断程序时,必须对他进行初始化。一般的程序过程是:

a.                       首先:用VICIntSelect寄存器对该中断进行选择时IRQ中断还是FIQ中断。

b.                       其次:用VICDefVectAddr寄存器存放非向量中断的地址

c.     最后:用VICIntEnable使该中断使能

 

程序事例:

VICIntSelect = 0x00000000;      // 设置所有中断为IRQ中断

VICDefVectAddr0 = (int)IRQ_UART0; // 设置UART0非向量中断的地址

VICIntEnable = 0x00000040;      // 使能UART0中断

四综合:一个程序中既有向量中断和非向量中断

Eg;假设UART0和SPI0 产生中断请求,它们被分配为向量IRQ(UART0的优先级高于SPI0),而UARTI和I2C产生非向量IRQ,

程序:

VICIntSelect = 0x00000000; // 设置所有中断为IRQ中断

VICVectCntl0=0x26//UART0通道号为6优先级为0(最高)

VICVectCntl1=0x2A//SPI0通道号为10优先级为1

VICVectAddr0=(int)UART0_IRQ;

VICVectAddr1=(int)SPI0_IRQ;

VICDefAddr=//保存非向量UART1和I2C 终端服务的地址;

VICIntEnable=0x6c0//SPI0,I2C,UART1,UART0在bit10,bit9,bit7和bit6=1

四.ARM中断程序编写之外部中断

前言:VIC中断控制器定义了4个外部中断,中断号为EINT0(14),

EINT1(15),EINT2(16),EINT3(17)用来给用户进行编写外部中断(例如按键中断。。。)

1.     在编写外部中断事先要对引脚功能选择寄存器(PINSEL0)进行配置

(参照具体型号的ARM数据手册,此处以LPC2230进行配置)在LPC2230中:

Eg:PINSEL1 = 3<<8;      // 设置管脚连接,P0.20设置为EINT3

 

2第二部外部中断还要对外部中断方式寄存器(EXTMODE)进行配置来选择每个EINT脚是电平触发还是边沿触发。

AEXTMODE(外部中断方式寄存器):总共有8位

第0位:对第0位写入1表示对EINT0使用边沿触发,反之,写入0表示对EINT0使用电平触发。

第1位:功能和上面相似只是对EINT1进行配置

第2位:是对EINT2进行配置

第3位:是对EINT3进行配置

第4~7位:保留

Eg;EXTMODE = 1<<3; // 设置EINT3中断为边沿触发模式

EXTMODE = 0<<3;          // 设置EINT3中断为电平触发模式

3第三部外部中断还要对外部中断极性寄存器进行配置(EXTPOLAR)进行配置(在电平触发方式中,EXTPOLAR寄存器用来选择相应引脚是高电平或低电平有效。在边沿触发方式中,EXTPOLAR寄存器用来选择引脚上升沿或下降沿有效)

A. EXTPOLAT(外部中断极性寄存器)总共有8位

第0位:是对EINT0进行配置,对该位写入1表示时表示

EINT0高电平或上升沿有效。反之,对该位写入0表示表示EINT0低电平或下降沿有效

第1位:是对EINT1进行配置。功能和上面类似。

第2位:是对EINT2进行配置。功能和上面类似

第3位:是对EINT3进行配置。功能和上面类似

第4~7位:保留位。

Eg:  EXTPOLAR = 0x00;     // 设置EINT3中断为下降沿触发

         EXTPOLAR = 0x00;// 设置EINT3中断为低电平有效

4.第四部配置中断选择寄存器VICIntSelect

功能和前面的类似

Eg; VICIntSelect = 0x00000000; // 设置所有中断分配为IRQ中断

5若外部中断为向量中断则对向量控制寄存器0~15(VICVectCntl0~15)

进行配置。若为非向量中断则此步骤可省掉。

Eg: VICVectCntl0 = 0x20|17; // 分配EINT3中断到向量中断0,0x20表示向量IRQ使能,1<<17表示EINT3在VIC通道17号

6配置外部中断服务程序的地址:

a.若为向量中断则配置向量地址寄存器(VICVectAddrx)

a.     b.若为非向量中断则配置默认向量地址寄存器VICDefVectAddr

eg:  VICVectAddr0 = (int)IRQ_Eint3;      // 设置向量中断服务程序地址IRQ_Eint3(为函数名,可随意起)

VICDefVectAddr = (int)IRQ_Eint3;             // 设置非向量中断服务程序地址

7.清除外部中断标志

配置外部中断标志寄存器(EXTINT)

在初始化时,一定要对EXTINT引脚进行初始化,否则会进入异常模式。

A.    通过对EXINT寄存器写人1来将其清零来清除外部中断标志

B.     EXTINT总共有8位

第0位:是对EINT0进行配置,写入1对外部中断EINT0中断进行清除

第1位:是对EINT1进行配置,写入1对外部中断EINT1中断进行清除。

第2位:是对EINT2进行配置,写入1对外部中断EINT2中断进行清除。

第3位:是对EINT3进行配置,写入1对外部中断EINT3中断进行清除。

第4~7位:保留位.

Eg: EXTINT = 1<<3;              // 清除EINT3中断标志

8.对中断使能寄存器(VICIntEnable)进行配置

功能和前面说的类似

Eg: VICIntEnable = 1<<17; // 使能EINT3中断,EINT3在VIC通道17号

注:编写外部中断程序时初始化实例:

1.初始化外部中断3,用向量中断,为边沿触发。

PINSEL1 = 3<<8; // 设置管脚连接,P0.20设置为EINT3

EXTMODE = 1<<3;  // 设置EINT3中断为边沿触发模式

EXTPOLAR = 0x00;  // 设置EINT3中断为下降沿触发

VICIntSelect = 0x00000000;            // 设置所有中断分配为IRQ中断

VICVectCntl0 = 0x20|17;            // 分配EINT3中断到向量中断0

VICVectAddr0 = (int)IRQ_Eint3;    // 设置中断服务程序地址

EXTINT = 1<<3;        // 清除EINT3中断标志  ,次步不能少

VICIntEnable = 1<<17;  // 使能EINT3中断,EINT3在VIC通道17号

2.     初始化外部中断为EINT3,用非向量中断,为电平触发

PINSEL1 = 3<<8; // 设置管脚连接,P0.20设置为EINT3

EXTMODE = 0<<3; // 设置EINT3中断为电平触发模式

EXTPOLAR = 0x00; // 设置EINT3中断为低电平触发

VICIntSelect = 0x00000000;// 设置所有中断分配为IRQ中断

VICDefVectAddr = (int)IRQ_Eint3;       // 设置中断服务程序地址

EXTINT = 1<<3;              // 清除EINT3中断标志  ,次步不能少

VICIntEnable = 1<<17;  //使能EINT3中断,EINT3在VIC通道17号

注:1.在编写中断服务函数时,外部中断为电平触发和边沿触发有区别

3.     在zlg模版中编写中断服务函数时,函数名的前缀是 __irq

函数实例:

1>用外部中断3,用向量中断,为边沿触发的中断服务函数的程序

void   __irq IRQ_Eint3(void)

    uint32  i;

    i = IO0SET;                                               // 读取当前B1控制值

    if( (i&BEEPCON)==0 )                          // 控制B1输出取反

    { 

        IO0SET = BEEPCON;

    }

    else

    {

        IO0CLR = BEEPCON;

    }

       EXTINT = 1<<3;    // 清除EINT3中断标志,1<<3 等价于 0x08

        VICVectAddr = 0;   // 向量中断结束

}               

此中断函数实现的功能时当有按键按下时会蜂鸣。

注:

           1.每个中断服务函数的函数名前缀必须加__irq

2在中断服务程序最后要清除中断标志EXTINT = 1<<3,以及给VICVectAddr寄存器写入0;VICVectAddr = 0

  2>初始化外部中断为EINT3,用非向量中断,为电平触发

void   __irq IRQ_Eint3(void)

    uint32  i;

    i = IO0SET;                                                // 读取当前B1控制值

    if( (i&BEEPCON)==0 )                            // 控制B1输出取反

    { 

        IO0SET = BEEPCON;

    }

    else

    { 

        IO0CLR = BEEPCON;

    }

    /* 等待外部中断信号恢复为高电平(若信号保持为低电平,中断标志会一直置位) */

    while( (EXTINT&1<<3)!=0 )  

    { 

        EXTINT = 1<<3;         // 清除EINT3中断标志,

    }

VICVectAddr = 0;               // 向量中断结束

}

   注:

在用电平触发时在中断服务程序最后要清除中断标志时要用

while( (EXTINT&1<<3)!=0 ) 

    { 

        EXTINT = 1<<3;         // 清除EINT3中断标志,

    }

(因为等待外部中断信号恢复为高电平(若信号保持为低电平,中断标志会一直置位)这一点和边沿触发有区别。 

注:1.中断使能清零寄存器VICIntEnClr:那1位置1则用来屏蔽该位的中断

1.     当有多个中断源被设置为非向量IRQ中断时,需要在用户程序中识别中断源,并分别作出处理。所以非向量IRQ中断响应延时相对较长。

2.     中断状态寄存器:

a.如果使用了多个非向量IRQ中断或多个FIQ中断,那么在发生中断后要在程序中查找中断源。通过IRQ状态寄存器和FIQ状态寄存器可以了解到这些中断源的中断请求状态。

b. 任何在VIC中使能的中断都会把中断请求反映在“所有中断寄存器(VICRawIntr)中

c.所有中断状态寄存器(VICRawIntr):当某位为1时表示对应位的中断源产生中断请求。

d.FIQ状态寄存器(VICFIQStatus):当某位为1时表示对应位的中断产生FIQ中断请求。

e.IRQ状态寄存器(VICIRQStatus):当某位为1时表示对应位的中断源产生IRQ中断请求