您的位置:首页 > 其它

ARM系统中断产生流程

2011-06-20 14:40 169 查看
++++++++++++++++++++++++++++++++++++++++++

本文系本站原创,欢迎转载! 转载请注明出处:

/article/1433078.html

++++++++++++++++++++++++++++++++++++++++++



中断源按照硬件位置分为外部中断源和内部中断源,外部中断源和内部中断源又包含子外部中断源和子内部中断源,如上图所示(画了一整天)。

1.
子内部中断源的产生

以UART0接收数据产生INT_RXD0中断为例,INT_RXD0产生后进入SUBSRCPND子中断源暂存寄存器,设置INT_RXD0对应的中断位,中断信号经过INTSUBMSK子中断屏蔽寄存器,如果INT_RXD0信号对应位没有被置位(屏蔽掉),中断信号继续向前传递,经过子内部中断源聚合器,将INT_RXD0聚合成对应的中断源信号INT_UART0,设置SRCPND中断源暂存寄存器里INT_UART0位,经过INTMSK中断屏蔽寄存器,如果INT_UART0信号没有被屏蔽掉,中断信号进入INTMOD中断模式寄存器判断是否为快速中断,如果被编程为快速中断,直接打断ARM内核,进入中断处理,如果中断信号为一般中断,进入中断优先级仲裁器进入优先级仲裁,如果INT_UART0信号为最高优先级或只有INT_UART0中断信号产生,则该中断信号被记录到INTPND最高优先级中断暂存寄存器,同时设置INTOFFSET的值为中断号28,最终将中断信号打断ARM内核进行中断处理。如果同时产生多个中断且INT_UART0不是最高优先级,则该中断信号不会被处理,等最高优先级信号处理完后,再次进行优先级仲裁,也就是说中断信号不消失,一直保存在SRCPND里,只到被处理为止。

2.
内部中断源的产生

该过程在子内部中断处理过程中已经包含,中断信号产生后直接进入SRCPND里,然后经历上述子内部中断后期处理过程。

3.
子外部中断的产生

外部中断源共有24个,其中EINT0~EINT3为外部中断源,EINT4_7,EINT8_23为复合中断源,他们包含有子外部中断源。

由于外部硬件直接挂接到I/O Ports(详见S3C2440A硬件手册第9章)上的,我们要想让外设硬件中断得到处理,要先从EINT0~EINT23里选择中断信号,我们以EINT11为例,介绍子外部中断处理过程。

通常CPU内部引出引脚都是复用的,也就是说一根CPU引脚可以有多种功能,可以设置其为输入信号线,输出信号线或中断信号线,要想让硬件产生中断,首先要对可以产生中断的引脚进行编程,设置该引脚为中断信号线。EINT11中断信号对应CPU引脚为GPG3,通过设置GPGCON[7:6]
= 0b10,可以设置该引脚为中断信号线。

表3-14 GPGCON寄存器



设置了CPU管脚为中断信号线之后,还要通过设置EXTINT0寄存器来指定中断信号的触发方式:高电平触发,低电平触发,电平上升沿,下除沿,双沿触发。



图3-9
电平信号触发示意图

由于按键按下时让它产生中断,也就是从高电平变为低电平时产生(上节按键中断原理),因此我们设置EINT11中断信号的触发方式为下降沿触发,EXTINT1[14:12]
= 0b01x

表3-15 EXTINT1寄存器



设置完触发方式之后,当外设中断信号线上的电平达到触发条件时,通过外部中断产生器产生中断信号,然后将子外部中断暂存寄存器EINTPND中对应的EINT11位置1,中断信号再进入EINTMSK子外部中断屏蔽寄存器,如果EINT11中断源信号没有被屏蔽,则EINT11中断信号进入子外部中断聚合器,复合成EINT8_23中断信号,然后再经历与前面子内部中断信号一样的处理机制。

(1)EINTPEND外部中断暂存寄存器

表3-16外部中断暂存寄存器(EINTPEND)

寄存器名

地址

是否读写

描述

复位默认值

EINTPEND

0x560000A8

R/W

外部中断信号暂存寄存器

0:没有中断请求信号

1:中断请求信号产生

0x0000000

EINTPEND



描述

初始值

EINT23

[23]

0 = 未产生中断 1 =
产生中断

0









EINT4

[4]

0 = 未产生中断 1 =
产生中断

0

保留位

[3:0]



0000

(2)EINTMASK外部中断屏蔽寄存器

表3-17外部中断屏蔽寄存器(EINTMASK)

寄存器名

地址

是否读写

描述

复位默认值

EINTMASK

0x560000A4

R/W

外部中断信号屏蔽寄存器

0:未屏蔽,中断可用

1:屏蔽中断信号

0x000FFFFF

EINTMASK



描述

初始值

EINT23

[23]

0 = 未屏蔽1 =
屏蔽中断

1









EINT4

[4]

0 = 未屏蔽1 =
屏蔽中断

1

保留位

[3:0]



1111

4.
外部中断源的产生

外部中断产生过程读者可以根据上面中断图自行分析。

按键控制LED灯实验

本实验分三个版本,分别针对三种开发板:友善之臂QQ2440,友善之臂MINI2440,天嵌TQ2440。每种开发板对应工程在:“sys_irq_开发板名”目录下。下面实验内容为针对MINI2440开发板。

head.s:

主要实现安装异常向量表,处理复位异常,初始化必要硬件,中断入口处理等功能。

;**********************************************************************

;
系统中断实验(MINI2440)

;**********************************************************************

GPBCON
EQU 0x56000010

GPBDAT
EQU 0x56000014

EXPORT SYS_IRQ

AREA SYS_IRQ,CODE,READONLY

ENTRY

;**********************************************************************

; 设置中断向量,除Reset和HandleIRQ外,其它异常都没有使用(如果不幸发生了,

; 将导致死机)

;**********************************************************************

; 0x00: 复位Reset异常

b Reset

; 0x04:
未定义异常(未处理)

HandleUndef

b HandleUndef

; 0x08:
软件中断异常(未处理)

HandleSWI

b HandleSWI

; 0x0c:
指令预取异常(未处理)

HandlePrefetchAbt

b HandlePrefetchAbt

; 0x10:
数据访问中止异常(未处理)

HandleDataAbt

b HandleDataAbt

; 0x14:
未使用异常(未处理)

HandleNotUsed

b HandleNotUsed

; 0x18:
一般中断异常,跳往HandleIRQ

b HandleIRQ

; 0x1c:
快速中断异常(未处理)

HandleFIQ

b HandleFIQ

Reset

; 复位异常处理入口

; 关闭看门狗

ldr r0, = 0x53000000

mov r1, #0

str r1, [r0]

bl initmem

ldr sp, =0x32000000
; 设置管理模式栈指针

IMPORT uart_init

bl uart_init
; UART串口初始化

IMPORT irq_init

bl irq_init
; 系统中断初始化

IMPORT key_init

bl key_init
; 按键初始化

IMPORT led_init

bl led_init
; LED灯初始化

msr
cpsr_cxsf, #0xd2
; 切换到中断模式下

ldr sp, =0x31000000
; 设置中断模式栈指针

msr cpsr_cxsf, #0x13
; 返回管理模式

ldr lr, =halt_loop
; 设置管理模式下返回地址

IMPORT main

ldr pc, =main
; 跳入主函数main里执行

;***********************************************************************

; 中断处理

;***********************************************************************

HandleIRQ

sub lr,lr,#4
; 修正返回地址

stmdb sp!,{r0-r12,lr}
; 保存程序执行现场

ldr lr,=int_return
; 设置中断处理程序返回地址

IMPORT handle_irq

ldr pc,=handle_irq
; 跳入中断处理程序

int_return
; 中断处理返回标签

ldmia sp!,{r0-r12,pc}^
恢复程序执行现场,返回继续执行

halt_loop

b halt_loop

initmem

ldr
r0, =0x48000000

ldr r1, =0x48000034

;ldr r2, =memdata

adr r2, memdata

initmemloop

ldr r3, [r2], #4

str r3, [r0], #4

teq r0, r1

bne initmemloop

mov pc,lr

memdata

DCD 0x22000000
;BWSCON

DCD 0x00000700
;BANKCON0

DCD 0x00000700
;BANKCON1

DCD 0x00000700
;BANKCON2

DCD 0x00000700
;BANKCON3

DCD 0x00000700
;BANKCON4

DCD 0x00000700
;BANKCON5

DCD 0x00018005
;BANKCON6

DCD
0x00018005 ;BANKCON7

DCD 0x008e07a3
;REFRESH

DCD 0x000000b1
;BANKSIZE

DCD 0x00000030
;MRSRB6

DCD 0x00000030
;MRSRB7

END
; 代码结束

该程序主要设置异常向量表,除了Reset异常和中断处理被处理以外,其它异常都未被处理,如果发生时,会产生死循环,Reset异常里主要实现了硬件的基本初始化,如:按键,LED灯等,设置栈指针,用于执行C程序,最后跳入C程序的main函数。在中断处理异常处理中首先修正返回地址,保存用户执行现场,跳入到中断处理例程中执行。

sys_init.c:

硬件初始化文件,里面包含LED,KEY的初始化函数。

#include "register.h"

#include "comm_fun.h"

#define
TXD0READY (1<<2) //发送数据状态OK

#define
RXD0READY (1)
//接收数据状态OK

/* UART串口初始化
*/

void uart_init()

{

GPHCON |= 0xa0; //GPH2,GPH3 used as TXD0,RXD0

GPHUP = 0x0;
//GPH2,GPH3内部上拉

ULCON0 = 0x03;
//8N1

UCON0 = 0x05;
//查询方式为轮询或中断;时钟选择为PCLK

UFCON0 = 0x00; //不使用FIFO

UMCON0 = 0x00;
//不使用流控

UBRDIV0 = 12;
//波特率为57600,PCLK=12Mhz

}

/* UART串口单个字符打印函数
*/

extern void putc(unsigned char c)

{

while( ! (UTRSTAT0 & TXD0READY) );

UTXH0 = c;

}

/* UART串口接受单个字符函数
*/

extern unsigned char getc(void)

{

while( ! (UTRSTAT0 & RXD0READY) );

return URXH0;

}

/* UART串口字符串打印函数
*/

extern int printk(const char* str)

{

int i = 0;

while( str[i] ){

utc( (unsigned char) str[i++] );

}

return i;

}

/*
按键初始化 */

int key_init()

{

//
设置K1,K2,K3,K4,K5,K6对应控制寄存器为中断模式

GPGCON = (2<<0) | (2<<6) | (2<<10) | (2<<12) | (2<<14) | (2<<22);

/*

01x falling edge triggered下降沿触发

10x Rising edge triggered上升沿触发

11x Both edge triggered双沿触发

*/

// 设置K1,K2,K3,K4,K5按键中断触发方式为上升沿触发

EXTINT1 = (3<<0) | (3<<12) | (3<<20) | (3<<24) | (3<<28);

EXTINT2 = (3<<12); //
设置K6按键中断触发方式为上升沿触

printk("按键初始化OK/r/n");

return 0;

}

/* Led1~Led4初始化*/

#define LED1
(1<<5) //LED1 GPBDAT[5]

#define LED2
(1<<6) //LED2 GPBDAT[6]

#define LED3
(1<<7) //LED3 GPBDAT[7]

#define LED4
(1<<8) //LED4 GPBDAT[8]

/*
点亮对应num号led灯
*/

extern int led_on(int num)

{

switch(num)

{

case 1:

GPBDAT = GPBDAT & ~LED1; break;

case 2:

GPBDAT = GPBDAT & ~LED2; break;

case 3:

GPBDAT = GPBDAT & ~LED3; break;

case 4:

GPBDAT = GPBDAT & ~LED4; break;

default:

return 0;

}

return num;

}

/*
关闭num号led灯
*/

extern int led_off(int num)

{

switch(num)

{

case 1:

GPBDAT = GPBDAT | LED1; break;

case 2:

GPBDAT = GPBDAT | LED2; break;

case 3:

GPBDAT = GPBDAT | LED3; break;

case 4:

GPBDAT = GPBDAT | LED4; break;

default:

return 0;

}

return num;

}

/*
关闭全部led灯
*/

extern int all_led_off(void)

{

GPBDAT = GPBDAT | LED1 | LED2 | LED3 | LED4;

return 0;

}

/* led灯初始化
*/

int led_init(void)

{

GPBCON = 0x15400; //设置GPB7为输出口

all_led_off();

printk("led初始化OK/r/n");

return 0;

}

/*
中断初始化 */

void irq_init(void)

{

// 打开KEY1~KEY6的屏蔽位

INTMSK &= ~(1<<5);

EINTMASK &= ~((1<<8) | (1<<11) | (1<<13) | (1<<14) | (1<<15) | (1<<19));

printk("中断初始化OK/r/n");

}

该文件是相关硬件初始化程序,主要包含了看门狗驱动,按键驱动,系统中断驱动,LED驱动。

handle_irq.c:

中断处理函数,查出中断源,中断处理,清除中断源。

#include "register.h"

#include "comm_fun.h"

#define EINT_Key_REQUEST
5 // Key中断源中断号(6个按键全部使用外部子中断)

#define K1_EINT_BIT
(1<<8) // K1外部子中断位

#define K2_EINT_BIT
(1<<11) // K2外部子中断位

#define K3_EINT_BIT
(1<<13) // K3外部子中断位

#define K4_EINT_BIT
(1<<14) // K4外部子中断位

#define K5_EINT_BIT
(1<<15) // K5外部子中断位

#define K6_EINT_BIT
(1<<19) // K6外部子中断位

/*
系统中断处理函数 */

void handle_irq()

{

unsigned long irqOffSet = INTOFFSET; //
取得中断号

all_led_off();
// 关闭全部Led灯

if(EINT_Key_REQUEST==irqOffSet){
// Key中断产生(6个按键使用一个总中断号)

if(K1_EINT_BIT & EINTPEND){

led_on(1);
// 点亮Led1

printk("Key1 pressed/r/n");

EINTPEND &= K1_EINT_BIT; // 清除外部子中断源

}else if(K2_EINT_BIT & EINTPEND){

led_on(2);
// 点亮Led2

printk("Key2 pressed/r/n");

EINTPEND &= K2_EINT_BIT; // 清除外部子中断源

}else if(K3_EINT_BIT & EINTPEND){

led_on(3);
// 点亮Led3

printk("Key3 pressed/r/n");

EINTPEND &= K3_EINT_BIT; // 清除外部子中断源

}else if(K4_EINT_BIT & EINTPEND){

led_on(4);
// 点亮Led4

printk("Key4 pressed/r/n");

EINTPEND &= K4_EINT_BIT;
// 清除外部子中断源

}else if(K5_EINT_BIT & EINTPEND){

all_led_off(1);
// 熄灭全部Led

printk("Key5 pressed/r/n");

EINTPEND &= K5_EINT_BIT; // 清除外部子中断源

}else if(K6_EINT_BIT & EINTPEND){

all_led_on();
// 点亮全部Led

printk("Key6 pressed/r/n");

EINTPEND &= K6_EINT_BIT; // 清除外部子中断源

}

}

SRCPND &= (1<<irqOffSet);
// 清除中断源

INTPND = INTPND;
// 清除中断结果

}

main.c:

包含主函数和延时函数,主要实现字符串的循环打印。

#include "register.h"

#include "comm_fun.h"

/*
延时 */

void delay(int msec)

{

int i, j;

for(i = 1000; i > 0; i--)

for(j = msec*10; j > 0; j--)

/* do nothing */;

}

/*
主函数 */

int main()

{

while(1)

{

printk("main函数在运行.../r/n");

delay(5); //delay

}

return 0;

}

++++++++++++++++++++++++++++++++++++++++++

本文系本站原创,欢迎转载! 转载请注明出处:

/article/1433078.html

++++++++++++++++++++++++++++++++++++++++++
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: