百家汽车网
您的当前位置:首页嵌入式-中断实验分析

嵌入式-中断实验分析

来源:百家汽车网


实验五 中断控制实验

(一) 实验目的

了解中断的作用;

掌握嵌入式系统中断的处理流程; 掌握ARM中断编程。

(二) 实验设备

计算机;ARM硬件仿真器;ARM开发板

(三) 实验硬件设置

在做实验之前,先将开发板电源接好,将仿真器的USB连线与电脑相连,通电,然后按核心板的复位键。

(四) 实验原理

1. 中断的基本概念

CPU与外设之间传输数据的控制方式通常有三种:查询方式、中断方式和DMA方式。DMA

方式将在后续实验中说明。查询方式的优点是硬件开销小,使用起来比较简单。但在此方式下,CPU要不断地查询外设的状态,当外设未准备好时,CPU就只能循环等待,不能执行其它程序,这样就浪费了CPU的大量时间,降低了CPU的利用率。为了解决这个矛盾,通常采用中断传送方式:即当CPU进行主程序操作时,外设的数据已存入输入端口的数据寄存器;或端口的数据输出寄存器已空,由外设通过接口电路向CPU发出中断请求信号,CPU在满足一定的条件下,暂停执行当前正在执行的主程序,转入执行相应能够进行输入/输出操作的子程序,待输入/输出操作执行完毕之后CPU再返回并继续执行原来被中断的主程序。这样CPU就避免了把大量时间耗费在等待、查询状态信号的操作上,使其工作效率得以大大地提高。能够向CPU发出中断请求的设备或事件称为中断源。系统引入中断机制后,CPU与外设(甚至多个外设)处于“并行”工作状态,便于实现信息的实时处理和系统的故障处理。中断方式的原理示意图如下所示。

图5-7 中断处理示意图

1) 中断响应

中断源向CPU发出中断请求,若优先级别最高,CPU在满足一定的条件下,可以中断当前程序的运行,保护好被中断的主程序的断点及现场信息。然后,根据中断源提供的信息,找到中断服务子程序的入口地址,转去执行新的程序段,这就是中断响应。

CPU响应中断是有条件的,如内部允许中断、中断未被屏蔽、当前指令执行完等。 2) 中断服务子程序

CPU响应中断以后,就会中止当前的程序,转去执行一个中断服务子程序,以完成为相应设备的服务。中断服务子程序的一般结构如下图所示。

图5-8 中断服务子程序处理流程

▼ 保护现场(由一系列的压栈指令完成)。目的是为了保护那些与主程序中有冲突的寄存器,(如R0,R1,R2等),如果中断服务子程序中所使用的寄存器与主程序中所使用的寄存器等没有冲突的话,这一步骤可以省略。

▼ 中断处理,中断处理程序在检查到相应的中断源后,调用对应的中断处理程序完成。 ▼ 恢复现场并返回(由一系列的出栈指令完成)。是与保护现场对应的,但要注意数据恢复的次序,以免混乱。

由于中断服务子程序需要打断主程序的执行,因此其处理应该及时完成,较长时间的延时将导致系统性能严重下降。

(五) 实验关键代码及使用的寄存器

S3C44B0X的中断控制器包括5类寄存器:中断控制寄存器、中断状态寄存器、中断模式寄存器、中断屏蔽寄存器和中断清除寄存器。

1) 中断控制寄存器

该控制寄存器是处理器总的中断控制,包括中断模式是矢量模式还是非矢量模式,是否使能IRQ模式的中断,是否使能FIQ模式的中断,具体说明如下:

表5-3 中断控制寄存器

寄 存 器 名 称 INTCON 地 址 0x01E00000 读 写 状 态 R/W 描 述 中断控制寄存器 复 位 值 0x7 INTCON 保留 V 位 3 2 0 IRQ禁止/使能向量模式 0:向量中断模式 1:非向量中断模式 I 1 使能CPU的IRQ中断,在使用IRQ中断之前,必须清除该位 0:IRQ中断使能 1:IRQ中断禁止 F 0 使能CPU的FIQ中断,在使用FIQ中断之前,必须清除该位 0:FIQ中断使能 1:FIQ中断禁止 1 1 描 述 初 始 状 态 0 1 2) 中断状态寄存器

该寄存器用于检查中断来源,该寄存器是只读属性的。

表5-4 中断状态寄存器

寄 存 器 名 称 INTPND 地 址 0x01E00004 读 写 状 态 R 描 述 指示中断请求状态 0:中断已被响应 1:有中断请求 复 位 值 0x0 3) 中断模式寄存器

用于设置相应中断的工作模式,是IRQ模式还是FIQ模式。

表5-5 中断模式寄存器

寄 存 器 名 称 INTMOD 地 址 0x01E00008 读 写 状 态 R/W 描 述 中断模式寄存器 0:IRQ模式 1:FIQ模式 复 位 值 0x0 4) 中断屏蔽寄存器

表5-6 中断屏蔽寄存器

寄 存 器 名 称 INTMSK 地 址 0x01E0000C 读 写 状 态 R/W 描 述 确定哪一个中断源被屏蔽,屏蔽的中断源将不引发中断 0:中断服务有效 1:中断服务屏蔽 复 位 值 0x7FFFFFF 5) 中断清除寄存器

中断处理之后需要清除相应的标志位,中断清除寄存器说明如下:

表5-7 中断清除寄存器

寄 存 器 名 称 I_ISPC 地 址 0x01E00024 读 写 状 态 W 描 述 IRQ中断请求清0寄存器 F_ISPC 0x01E0003C W FIQ中断请求清0寄存器 未定义 复 位 值 未定义 4. 44B0中断处理

S3C44B0X处理器的中断处理与其他CPU的处理模式基本上是一致的,只是由于它引入了几种不同的处理器模式,使中断处理变得更加容易。其典型的步骤如下:

1) 保存现场:当系统出现中断时,处理器首先要做的就是保存现场,这一过程包括:保存当前的PC值到lr中,保存当前的程序运行状态到spsr中。值得注意的就是由于ARM7采用3级流水线结构,此时的PC值实际上等于当前指令地址加上8(ARM指令时),所以返回时还需要将保存的PC值减4;

2) 模式切换:当处理器完成现场保护后,就进入中断模式,并将PC值置为一个固定的

值0X00000018,这也就是IRQ模式的中断入口地址。在中断模式下,有两个的寄存器R13、R14,这样可以便于中断程序使用自己特有的堆栈。但这样随之而来产生一个问题,就

是中断处理时堆栈溢出保护的问题,需要我们认真地估计堆栈的大小,同时在中断处理时也要尽量减少函数调用的层次,否则将产生一些不可预知的错误;

3) 获取中断源:所有的IRQ中断都从0X00000018开始执行,通常在该地址处放一条跳转指令,进一步跳到我们的中断程序中;

4) 处理中断:在中断程序中需要进一步获取中断源,即谁引发了该中断,然后通过查

表获取相应中断的处理程序入口,并调用对应的函数;

5) 中断返回,恢复现场:在返回时需要恢复处理器模式,包括恢复中断处理用到的所有寄存器、恢复被中断的程序运行状态到CPSR,并跳转到被中断的主程序。

下图为JX44B0教学实验系统中处理外部中断0的流程:

图5-8 JX44B0中断处理示意图

中断的入口代码(汇编代码):

0X00000018: …… 0X0C000020:

HandlerIRQ:

b

HandlerIRQ

LDR

pc, =0X0C000020

sub sp,sp,#4 stmfd sp!,{r0} ldr r0,[r0]

/* 为中断分发例程入口地址预留栈空间 */ /* 保存R0 */

/* 将中断分发例程入口地址保存到R0中*/

ldr r0,=HandleIRQ /* 将中断分发例程入口地址指针保存到R0中 */ str r0,[sp,#4] /* 将中断分发例程入口地址保存到预留的堆栈空间 */ ldmfd sp!,{r0,pc} /* 将R0和中断分发例程入口地址出栈,这条指令也 */

/*实现了一个跳转 */

上述代码实际上就是一个三级跳,即从FLASH中跳到了RAM的中断入口,然后又从中断

入口跳到中断分发例程入口。在此我们有一个前提条件,即必须在HandleIRQ地址处保存正确的分发例程入口地址,如使用下面代码后IsrIRQ就是中断分发例程:

ldr r0,=HandleIRQ ldr r1,=IsrIRQ str r1,[r0]

中断分发例程可以采用汇编语言和C语言两种格式编写,下面将分别列出这两种方式。 1) 用汇编代码编写的中断分发例程:

IsrIRQ: /*using I_ISPR register.*/

sub lr,lr,#4

stmfd sp!,{lr} /* 保存中断返回的PC值 */

stmfd sp!,{r0-r4} /* 备份寄存器R0-R4 */ sub sp,sp,#4 /* 为PC预留栈空间 */ stmfd sp!,{r8-r9} /* 备份寄存器R8-R9 */ ldr r9,=I_ISPR /* 读取中断状态 */ ldr r9,[r9]

cmp r9, #0x0 /* 检查中断状态 */ beq i2

mov r8,#0x0 /* R8保存中断表的偏移 */ i0: /* 逐位检查中断状态 */ movs r9,r9,lsr #1 bcs i1 b i0

add r8,r8,#4

/* 如果该位等于1,则处理这一中断 */ /* 修改当前的中断偏移 */

/* 处理下一比特 */

i1:

ldr r9,=HandleADC /* HandleADC位于中断向量表起始位置,我们将该地址用作是中断向

量表的基地址 */

add r9,r9,r8

/* 计算入口地址指针:中断基地址加上偏移 */

/* 将入口地址保存到堆栈,并移动堆栈指针 */

ldr r9,[r9] /* 从地址向量表中获取入口地址 */ str r9,[sp,#8]

mov lr,pc /* 保存当前PC*/ ldmfd sp!,{r8-r9,pc} /* 调用中断例程 */

ldmfd sp!,{r0-r4, pc}^/* 中断返回,并恢复中断前的处理器模式*/ i2:

ldmfd sp!,{r8-r9} /* 如果当前没有任何中断,直接返回 */

add sp,sp,#4 /* 移动堆栈指针,该空间由第4句指令预留 */ ldmfd sp!,{r0-r4, pc}^/* 中断返回,并恢复中断前的处理器模式*/

2) 用C代码编写的中断分发例程:

如果采用GNU编译器,需要将该函数定义为中断类型,使用关键字:__attribute__

typedef (*ISR_ROUTINE_ENTRY)(void);

void IsrIRQ() __attribute__ ((interrupt(\"IRQ\"))); void IsrIRQ() {

int count = 0;

unsigned int isr_pending;

unsigned int isr_mask = 0x00000001;

unsigned int isr_mask_set = rINTMSK; /* 读取中断掩码 */ ISR_ROUTINE_ENTRY isr_routine_entry = (ISR_ROUTINE_ENTRY)0x0;

((interrupt(\"IRQ\")))。如下所示代码为C语言的IsrIRQ实现:

}

isr_pending = (rINTPND & ~isr_mask_set); /* 读取中断状态 */ /* 查表 */ while(isr_mask) { }

/* 调用中断服务例程 */

if(isr_routine_entry) (*isr_routine_entry)();

if(isr_pending&isr_mask) { }

count+=4; isr_mask <<= 1;

/* 找到中断源,获取中断例程入口地址 */

isr_routine_entry = (ISR_ROUTINE_ENTRY)(*(int*)(HandleADC+count)); break;

中断处理例程(该函数无需定义为中断类型)

void EINT0_Isr() { }

rI_ISPC=BIT_EINT0;/* 清除中断标志 */ ……

中断向量表中各个中断的偏移:

表5-8 中断向量表中各个中断的偏移

中断源 ADC(AD转换中断) RTC(实时时钟中断) …… 向量表的偏移 0X20 0X24 (六) 实验内容 1)编译/执行程序

2)跟踪/调试程序 3)断点的设置与取消。 4)下载程序与调试

(七) 实验步骤

1. 参照模板工程interrupt(modules\\interrupt\\interrupt.apj),新建一个工程interrupt,添加相应的文件,并修改interrupt的工程设置;

2. 创建interrupt.c并加入到工程interrupt中; 3. 编写中断分发例程IsrIRQ;

4. 注册外部中断0处理函数ext0_int_isr;

5. 实现外部中断0处理函数ext0_int_isr,在其中实现LED开关功能;

6. 编译interrupt;

7. 下载程序并运行,按下按键EXTINT0将引发一次外部中断,并在中断处理函数中闪灯。

(八) 实验报告要求

1. 中断处理的主要步骤有哪些?试说明每一步的主要工作。 2. 编写程序处理定时中断;

3. 简述S3C44B0X非矢量中断的处理步骤。

因篇幅问题不能全部显示,请点此查看更多更全内容