Arm920T寄存器简单介绍:
R1-R15:通用寄存器
R13:栈指针寄存器
R14:程序连接寄存器,当执行BL子程序调用指令时,R14中得到R15(程序计数寄存器pc)的备份,而当
发生中断或异常时,对应的R14_svc、R14_irq等保存R15返回值。
R15:程序计数器pc
CPSR:当前程序状态寄存器
1、T位(1位) Thumb/Arm。
2、I位与F位(5、6位)IRQ中断、FIQ中断开关。
SPSR:程序状态保存寄存器,SPSR中保存前一个工作模式的CPSR值。
异常发生时,将切换进入相应的异常模式,ARM920T cpu核自动完成如下工作,注意是自动完成。
1、在异常模式的连接寄存器R14中保存前一个工作模式的下一条即将执行的指令地址(R15->R14_xxx),
对于ARM状态,这个值是当前pc值加4或加8。
2、将CPSR的值复制到异常模式的SPSR(CPSR->SPSR)。(所用模式共用一个CPSR,各异异常模式有一个
自己的SPSR,用于保存前一个模式下的CPSR值)。
3、将CPSR的工作模式位设置为这个异常模式对应的工作模式。
4、令pc值等于这个异常模式在异常向量表中的地址,即跳转去执行异常向量表中的相应指令。
相反地,从异常模式回到之前的工作模式,需要通过软件完成如下事情:
1、将异常模式下的R14减去一个适当值后赋给pc寄存器。
2、将SPSR的值复制回CPSR。
退出异常时pc的值计算方法见韦东山的《嵌入式Linux应用开发完全手册》表9.1 p146。
中断处理过程:
1、中断控制器汇集各类外设发出的中断信号,然后告诉cpu。
2、cpu保存当前程序的运行环境,调用中断服务程序(ISR,Interrupt Service Rountine)。
3、在ISR中通过读取中断控制器,外设的相关寄存器来识别这是哪一个中断,并进行相应的处理。
4、清除中断,通过读写中断控制器和外设的相关寄存器实现。
5、恢复运行环境,继续执行。
各寄存器用途:
SUBSRCPND:标识INT_RXD0、INT_TXD0等中断是否已经发生。
INTSUBMSK:屏蔽SUBSRCPND寄存器所标识的中断。
SRCPND:每一位用来表示一个(或一类)中断是否已经发生,两类中断,这两类中断是:使用
SUBSRCPND/INTSUBMSK控制的中断request source(with sub register)使用SRCPND/INTMSK
控制的中断request source(without sub register)。
INTMSK:屏蔽SRCPND寄存器所标识的中断。
INTMOD:某位被置1时,它对应的中断被设为FIQ。同一时刻只能设置其中的一位,只能设置一个FIQ。
PRIORITY:优先级仲裁器。多个普通中断同时发生的时候,根据这个寄存器找出优先级最高的处理。
INTPND:cpu即将处理的中断标志。同一时刻只能设置其中1位,ISR中可根据这个位确定发生的是哪个中断。
INTOFFSET:表示INTPND哪位被置1。
中断有两类,是request_source(without sub register)和request_source(with usb register),这两类对
应不同的屏蔽寄存器(INTMSK和INTSUBMSK)和发生中断的标志寄存器(SRCPND和SUBSRCPND)。
如果被触发的中断有快速中断(IFQ)(INTMOD寄存器中为1的为对应的是FIQ),则cpu进如快中断处理。若几个IRQ同时,则选出优先级最高的,其在INTPND寄存器中的相应位被置1,然后cpu进入中断模式处理。
中断服务程序可通过读取INTPND寄存器或者INTOFFSET寄存器来确定中断源。
优先级在PRIORITY寄存器设置。
中断使用:
(1)、设置好中断与快中断模式下的栈
(2)、准备好中断处理函数
1、异常向量
在异常向量表中设置好当进入中断模式或快中断模式时的跳转函数,他们的异常向量地
址分别是0x00000018、0x0000001c。
2、中断服务程序(ISR)
跳转函数最终调用具体的中断服务函数,对于IRQ、读取INTPND寄存器或INTOFFSET寄存
器的值来确定中断源,然后分别处理,对于FIQ,无须判断。
3、清除中断
可在调用ISR之前,也可以在ISR之后,取决于是否嵌套。
清除顺序:1外设 2SUBSRCPND(用到的话)SRCPND中相应的位 3 轻INTPND相应位。
(3)进入、退出中断模式或快速中断模式是,需要保存、恢复被中断程序的运行环境。
1、对于IRQ,进入和退出的代码如下:
中断触发条件(低电 平触发、高电平触发、下降沿触发还是上升沿触发)等。一些中断拥有自己的屏
蔽寄存器,还要开启他。
(5)对于“request sources(without sub-register)"中的中断,将INTSUBMSK寄存器中相应的位设为0。
(6)确定使用此中断的方式:FIQ或IRQ。
如果是FIQ,则在INTMOD寄存器中设置相应的位为1.
如果是IRQ,则在RIORITY寄存器中设置优先级。
(7)如果是IRQ,将INTMSK寄存器中相应位设为0(IFQ不受INTMSK寄存器控制)。
(8)设置CPSR寄存器中的I-bit(对于IRQ)或F-bit(对于FIQ)为0,使能IRQ或IFQ。
中断实例:在JZ2440开发板上,把K1-K4四个按键所接的CPU引脚设成外部中断功能。本程序的main函数是一
个不做任何事情的无限循环,程序的功能完全靠中断来驱动:当按下某个按键时,CPU调用其中断服务程序
R1-R15:通用寄存器
R13:栈指针寄存器
R14:程序连接寄存器,当执行BL子程序调用指令时,R14中得到R15(程序计数寄存器pc)的备份,而当
发生中断或异常时,对应的R14_svc、R14_irq等保存R15返回值。
R15:程序计数器pc
CPSR:当前程序状态寄存器
1、T位(1位) Thumb/Arm。
2、I位与F位(5、6位)IRQ中断、FIQ中断开关。
SPSR:程序状态保存寄存器,SPSR中保存前一个工作模式的CPSR值。
异常发生时,将切换进入相应的异常模式,ARM920T cpu核自动完成如下工作,注意是自动完成。
1、在异常模式的连接寄存器R14中保存前一个工作模式的下一条即将执行的指令地址(R15->R14_xxx),
对于ARM状态,这个值是当前pc值加4或加8。
2、将CPSR的值复制到异常模式的SPSR(CPSR->SPSR)。(所用模式共用一个CPSR,各异异常模式有一个
自己的SPSR,用于保存前一个模式下的CPSR值)。
3、将CPSR的工作模式位设置为这个异常模式对应的工作模式。
4、令pc值等于这个异常模式在异常向量表中的地址,即跳转去执行异常向量表中的相应指令。
相反地,从异常模式回到之前的工作模式,需要通过软件完成如下事情:
1、将异常模式下的R14减去一个适当值后赋给pc寄存器。
2、将SPSR的值复制回CPSR。
退出异常时pc的值计算方法见韦东山的《嵌入式Linux应用开发完全手册》表9.1 p146。
中断处理过程:
1、中断控制器汇集各类外设发出的中断信号,然后告诉cpu。
2、cpu保存当前程序的运行环境,调用中断服务程序(ISR,Interrupt Service Rountine)。
3、在ISR中通过读取中断控制器,外设的相关寄存器来识别这是哪一个中断,并进行相应的处理。
4、清除中断,通过读写中断控制器和外设的相关寄存器实现。
5、恢复运行环境,继续执行。
各寄存器用途:
SUBSRCPND:标识INT_RXD0、INT_TXD0等中断是否已经发生。
INTSUBMSK:屏蔽SUBSRCPND寄存器所标识的中断。
SRCPND:每一位用来表示一个(或一类)中断是否已经发生,两类中断,这两类中断是:使用
SUBSRCPND/INTSUBMSK控制的中断request source(with sub register)使用SRCPND/INTMSK
控制的中断request source(without sub register)。
INTMSK:屏蔽SRCPND寄存器所标识的中断。
INTMOD:某位被置1时,它对应的中断被设为FIQ。同一时刻只能设置其中的一位,只能设置一个FIQ。
PRIORITY:优先级仲裁器。多个普通中断同时发生的时候,根据这个寄存器找出优先级最高的处理。
INTPND:cpu即将处理的中断标志。同一时刻只能设置其中1位,ISR中可根据这个位确定发生的是哪个中断。
INTOFFSET:表示INTPND哪位被置1。
中断有两类,是request_source(without sub register)和request_source(with usb register),这两类对
应不同的屏蔽寄存器(INTMSK和INTSUBMSK)和发生中断的标志寄存器(SRCPND和SUBSRCPND)。
如果被触发的中断有快速中断(IFQ)(INTMOD寄存器中为1的为对应的是FIQ),则cpu进如快中断处理。若几个IRQ同时,则选出优先级最高的,其在INTPND寄存器中的相应位被置1,然后cpu进入中断模式处理。
中断服务程序可通过读取INTPND寄存器或者INTOFFSET寄存器来确定中断源。
优先级在PRIORITY寄存器设置。
中断使用:
(1)、设置好中断与快中断模式下的栈
(2)、准备好中断处理函数
1、异常向量
在异常向量表中设置好当进入中断模式或快中断模式时的跳转函数,他们的异常向量地
址分别是0x00000018、0x0000001c。
2、中断服务程序(ISR)
跳转函数最终调用具体的中断服务函数,对于IRQ、读取INTPND寄存器或INTOFFSET寄存
器的值来确定中断源,然后分别处理,对于FIQ,无须判断。
3、清除中断
可在调用ISR之前,也可以在ISR之后,取决于是否嵌套。
清除顺序:1外设 2SUBSRCPND(用到的话)SRCPND中相应的位 3 轻INTPND相应位。
(3)进入、退出中断模式或快速中断模式是,需要保存、恢复被中断程序的运行环境。
1、对于IRQ,进入和退出的代码如下:
sub lr,lr,#4 @计算返回地址
stmdb sp!,{r0-r12,lr} @保存使用到的寄存器
...... @处理中断
ldmia sp!,{r0-r12,pc}^@中断返回
@ ^ 表示将spsr的值赋给cpsr
2、对于FIQ、进入和退出的代码如下:
sub lr,lr #4 @计算返回地址
stmdb sp!,{r0-r7,lr} @保存使用到的寄存器
…… @处理快速中断
ldima sp!,{r0-r7,pc}^ @ ^ 表示将spsr的值赋给cpsr
(4)根据具体中断,设置相关外设。比如对于GPIO中断,需要将相应的引脚的功能设为“外部中断”、设置
中断触发条件(低电 平触发、高电平触发、下降沿触发还是上升沿触发)等。一些中断拥有自己的屏
蔽寄存器,还要开启他。
(5)对于“request sources(without sub-register)"中的中断,将INTSUBMSK寄存器中相应的位设为0。
(6)确定使用此中断的方式:FIQ或IRQ。
如果是FIQ,则在INTMOD寄存器中设置相应的位为1.
如果是IRQ,则在RIORITY寄存器中设置优先级。
(7)如果是IRQ,将INTMSK寄存器中相应位设为0(IFQ不受INTMSK寄存器控制)。
(8)设置CPSR寄存器中的I-bit(对于IRQ)或F-bit(对于FIQ)为0,使能IRQ或IFQ。
中断实例:在JZ2440开发板上,把K1-K4四个按键所接的CPU引脚设成外部中断功能。本程序的main函数是一
个不做任何事情的无限循环,程序的功能完全靠中断来驱动:当按下某个按键时,CPU调用其中断服务程序
来点亮对应的LED。主要看一下head.S和interrupt.c
@******************************************************************************
@ 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
interrupt.c:
#include "s3c24xx.h"
void EINT_Handle()
{
unsigned long oft = INTOFFSET;
unsigned long val;
switch( oft )
{
// S2被按下
case 0:
{
GPFDAT |= (0x7<<4); // 所有LED熄灭
GPFDAT &= ~(1<<4); // LED1点亮
break;
}
// S3被按下
case 2:
{
GPFDAT |= (0x7<<4); // 所有LED熄灭
GPFDAT &= ~(1<<5); // LED2点亮
break;
}
// K4被按下
case 5:
{
GPFDAT |= (0x7<<4); // 所有LED熄灭
GPFDAT &= ~(1<<6); // LED4点亮
break;
}
default:
break;
}
//清中断
if( oft == 5 )
EINTPEND = (1<<11); // EINT8_23合用IRQ5
SRCPND = 1<<oft;
INTPND = 1<<oft;
}