1. ARM的中断模式有7种:
1. 用户模式: 用于平时的程序运行
2. 快速中断模式: 用于高速数据传输或者通道处理, 此模式的优先级最高 最容易被触发 32个中断只能有一个快速中断触发
3. 中断模式:用于普通的中断模式
4. 管理模式:操作系统使用的保护模式
5. 数据访问终止模式: 当数据或指令与读取终止时候进入此模式
6. 系统模式: 运行具有特权的操作系统任务
7. 未定义指令终止模式:当未定义的指令执行时进入该模式 可用于支持硬件仿真。
2. 首先是看PSR (program status register)
如果此寄存器的F-bit 设置成1 则arm不会再接受快速中断的请求。另外如果是I-bit 设置成了1 则CPU将会关闭所有的中断。
上面的这个图解释了除了LCD之外的中断的模式:
SRCPND 这个寄存器可以查询到我们 那个地方发生了中断
SUBSRCPND 这个寄存器是用来管理串口等11个次一级重要的中断的
SUBMASK 是用来屏蔽SUBSRCPND所提供的中断
MASK用来屏蔽SRCPND寄存器上面的中断
MODE:设置成1 的时候可以把此寄存器设置成快速中断模式
Priority 如下图:
此图说明优先级是由这六个仲裁器去抉择的。寄存器位ARB_Mode和ARB_SEL的组合可以实现优先级的转换 情形如下所示:
INTPND 寄存器 是记录哪一个中断拥有最高的优先级 且此寄存器只能有一位置位为1
下面来分析一下代码:
1 @******************************************************************************
2 @ File:head.S
3 @ 功能:初始化,设置中断模式、管理模式的栈,设置好中断处理函数
4 @******************************************************************************
5
6 .extern main
7 .text
8 .global _start
9 _start:
10 @******************************************************************************
11 @ 中断向量,本程序中,除Reset和HandleIRQ外,其它异常都没有使用
12 @******************************************************************************
13 b Reset
14
15 @ 0x04: 未定义指令中止模式的向量地址
16 HandleUndef:
17 b HandleUndef
18
19 @ 0x08: 管理模式的向量地址,通过SWI指令进入此模式
20 HandleSWI:
21 b HandleSWI
22
23 @ 0x0c: 指令预取终止导致的异常的向量地址
24 HandlePrefetchAbort:
25 b HandlePrefetchAbort
26
27 @ 0x10: 数据访问终止导致的异常的向量地址
28 HandleDataAbort:
29 b HandleDataAbort
30
31 @ 0x14: 保留
32 HandleNotUsed:
33 b HandleNotUsed
34
35 @ 0x18: 中断模式的向量地址
36 b HandleIRQ
37
38 @ 0x1c: 快中断模式的向量地址
39 HandleFIQ:
40 b HandleFIQ
41
42 Reset:
43 ldr sp, =4096 @ 设置栈指针,以下都是C函数,调用前需要设好栈
44 bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启
45
46 msr cpsr_c, #0xd2 @ 进入中断模式
47 ldr sp, =3072 @ 设置中断模式栈指针
48
49 msr cpsr_c, #0xd3 @ 进入管理模式
50 ldr sp, =4096 @ 设置管理模式栈指针,
51 @ 其实复位之后,CPU就处于管理模式,
52 @ 前面的“ldr sp, =4096”完成同样的功能,此句可省略
53
54 bl init_led @ 初始化LED的GPIO管脚
55 bl init_irq @ 调用中断初始化函数,在init.c中
56 msr cpsr_c, #0x53 @ 设置I-bit=0,开IRQ中断
57
58 ldr lr, =halt_loop @ 设置返回地址
59 ldr pc, =main @ 调用main函数
60 halt_loop:
61 b halt_loop
62
63 HandleIRQ:
64 sub lr, lr, #4 @ 计算返回地址
65 stmdb sp!, { r0-r12,lr } @ 保存使用到的寄存器
66 @ 注意,此时的sp是中断模式的sp
67 @ 初始值是上面设置的3072
68
69 ldr lr, =int_return @ 设置调用ISR即EINT_Handle函数后的返回地址
70 ldr pc, =EINT_Handle @ 调用中断服务函数,在interrupt.c中
71 int_return:
72 ldmia sp!, { r0-r12,pc }^ @ 中断返回, ^表示将spsr的值复制到cpsr
73
一些注解:
第46行:
msr cpsr_c, #0xd2
msr 的意思是把一个立即数存储到一个PSR(program status register)那么这个寄存器是cpsr_c 又被称作寄存器R16是记录状态的寄存器(请参见2440datasheet P72)
这个就是R16寄存器 其中设置中断的时候需要吧第七位和第六位都需要置成1 这样子一开始先关闭中断和快速中断。
后面五位设置成中断模式(参见datasheet P78)
第47行:
ldr sp, =3072 @ 设置中断模式栈指针
这里面的其实就是给中断分配一个内存区 这个数字可以“随意”取只要能让前面的程序有足够的内存就好。
第56行:
msr cpsr_c, #0x53 : 这里面是开总中断 在管理模式下
第64行:
sub lr, lr, #4 @ 计算返回地址 这里是ARM自己的特定值记住便好
第65行:
stmdb sp!, { r0-r12,lr } @ 保存使用到的寄存器 这里面stmdb(stm相当于Push and DB (Decrement Before))Ex: STMFD sp!, {r0-r5} ; Push onto a Full Descending Stack
这里的意思是 把R0~R12还有lr(返回值的内容)压入栈
ldmia sp!, { r0-r12,pc }^ @ 中断返回, ^表示将spsr的值复制到cpsr 第72行:LDM(相当于POP and ia Increment After ) 这句话表示把寄存器还原
Saved Process Status Registers (SPSRs)
Current Program Status Register (CPSR)