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)