嵌入式裸机程序之中断原理

1.中断简介

中断,指计算机运行过程中,出现异常后,计算机停止当前工作保存当前状态,然后转向对这些异常的处理,在处理完成后再返回到停止时的状态,继续运行。

2.S3C2440中断

S3C2440有60个中断源,这里只以其中的外部中断为例,以最简单的中断处理过程代码来分析中断。

中断处理之前需要先将各个IO引脚设置为中断功能,将指示灯的IO引脚设置为输出模式。在此之后,需要了解S3C2440的各组中断的指针位置。

如代码所示,在这段汇编代码中定义了各个中断的入口,本实验使用HandleIRQ这个入口地址,当出现中断信号时,程序跳转到0x18这个地址,然后再跳转到HandleIRQ这个函数。

HandleIRQ函数首先将当前寄存器状态入栈保存,然后再跳转到真正的中断服务程序。

在中断服务程序中,根据INTOFFSET寄存器的内容来做出相应的指示,在完成中断响应后需要手动清中断。

这样主程序不需要运行其他代码,中断的初始化、IO接口初始化也都在汇编文件中完成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
@******************************************************************************
@ File:head.S
@ 功能:初始化,设置中断模式、管理模式的栈,设置好中断处理函数
@******************************************************************************

.extern main
.text
.global _start
_start:
@******************************************************************************
@ 异常向量,本程序中,除Reset和HandleIRQ外,其它异常都没有使用
@******************************************************************************
b Reset

@ 0x04: 未定义指令中止模式的向量地址
HandleUndef:
b HandleUndef

@ 0x08: 管理模式的向量地址,通过SWI指令进入此模式
HandleSWI:
b HandleSWI

@ 0x0c: 指令预取终止导致的异常的向量地址
HandlePrefetchAbort:
b HandlePrefetchAbort

@ 0x10: 数据访问终止导致的异常的向量地址
HandleDataAbort:
b HandleDataAbort

@ 0x14: 保留
HandleNotUsed:
b HandleNotUsed

@ 0x18: 中断模式的向量地址
b HandleIRQ

@ 0x1c: 快中断模式的向量地址
HandleFIQ:
b HandleFIQ

Reset:
ldr sp, =4096 @ 设置栈指针,以下都是C函数,调用前需要设好栈
bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启

msr cpsr_c, #0xd2 @ 进入中断模式
ldr sp, =3072 @ 设置中断模式栈指针

msr cpsr_c, #0xd3 @ 进入管理模式
ldr sp, =4096 @ 设置管理模式栈指针,
@ 其实复位之后,CPU就处于管理模式,
@ 前面的“ldr sp, =4096”完成同样的功能,此句可省略

bl init_led @ 初始化LED的GPIO管脚
bl init_irq @ 调用中断初始化函数,在init.c中
msr cpsr_c, #0x53 @ 设置I-bit=0,开IRQ中断

ldr lr, =halt_loop @ 设置返回地址
ldr pc, =main @ 调用main函数
halt_loop:
b halt_loop

HandleIRQ:
sub lr, lr, #4 @ 计算返回地址
stmdb sp!, { r0-r12,lr } @ 保存使用到的寄存器
@ 注意,此时的sp是中断模式的sp
@ 初始值是上面设置的3072

ldr lr, =int_return @ 设置调用ISR即EINT_Handle函数后的返回地址
ldr pc, =EINT_Handle @ 调用中断服务函数,在interrupt.c中
int_return:
ldmia sp!, { r0-r12,pc }^ @ 中断返回, ^表示将spsr的值复制到cpsr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include "s3c2440.h"

void EINT_Handle()
{
unsigned long oft = INTOFFSET;
unsigned long val;

/*
* K1,K2,K3,K4对应GPF1、GPF4、GPF2、GPF0
* 即 EINT1, ETIN4, EINT2, EINT0
* oft为 1, 4, 2, 0 (对应INTMSK寄存器)
*/

switch( oft )
{
// K1被按下
case 1:
{
GPBDAT |= (0xF<<5); // 所有LED熄灭
GPBDAT &= ~(1<<5); // LED1点亮
break;
}

// K2被按下
case 4:
{
GPBDAT |= (0xF<<5); // 所有LED熄灭
GPBDAT &= ~(1<<6); // LED2点亮
break;
}

// K3被按下
case 2:
{
GPBDAT |= (0xF<<5); // 所有LED熄灭
GPBDAT &= ~(1<<7); // LED3点亮
break;
}

// K4被按下
case 0:
{
GPBDAT |= (0xF<<5); // 所有LED熄灭
GPBDAT &= ~(1<<8); // LED4点亮
break;
}

default:
break;
}

//清中断
if( oft == 4 )
EINTPEND = (1<<4); // EINT4_7合用IRQ4
SRCPND = 1<<oft;
INTPND = 1<<oft;
}

嵌入式裸机程序之中断原理
http://atime.cc/2017/02/03/嵌入式裸机程序之中断原理/
作者
ATIME
发布于
2017年2月3日
许可协议