s3c2440有60个中断源(其中15个为子中断源)。
31个32位的通用寄存器,6个程序状态寄存器。有6种工作模式(系统/用户模式,快中断模式,管理模式,数据访问中止模式,中断模式,未定指令中止模式)。每种模式都有16个通用寄存器和1(或2)个程序状态寄存器。
R15(pc)是程序计数器,R14(lr)是连接寄存器,在异常时自动保存pc备份,r13(sp)是栈指针寄存器。
CPSR是当状程序状态寄存器。其[7:0]为控制位,[7]为中断禁止位,[6]为快中断禁止位,[5]为CPU状态位,[4:0]为工作模式位。,
程序状态寄存器(PSR)的F位[6]设为1,禁用快速中断(FRQ)。
程序状态寄存器(PSR)的I位[7]设为1,禁用普通中断(IRQ)。
SPSR程序状态保存寄存器,用于在异常时保存CPSR,从异常返回时恢复CPSR。
中断的处理过程:
1,中断控制器汇集中断信号告诉CPU;
2,CPU自动保存当前运行的环境,调用中断服务程序ISR进行处理(lr=pc+4或+8,即当前指令地址的一下条;cpsr复制到spsr;pc值等于异常向量表中的地址,即转去执行异常向量表中的指令);
3,ISR通过读中断控制器相关寄存器,识别哪个中断发生了,进行相应处理;
4,清除中断;
5,恢复被中断的程序的运行环境(pc=lr-4或-8,spsr复制回cpsr),继续执行。
s3c2440中断控制器中有五个控制寄存器:中断源等待寄存器(SRCPND),中断模式寄存器(INTMOD),屏蔽寄存器(INTMSK),优先级寄存器(PRIORITY),中断等待寄存器(INTPND)。
SRCPND寄存器各位对应不同的中断,其中外部中断EINT4-7共用bit4,EINT8-23共用bin5。各位初始值为0,当中断发生时,对应位值改为1。
INTMOD寄存器各位用于标记该位对应的中断是模式,0为IRQ,1为FRQ。只允许有一个中断设为FRQ。初始值都为0。
INIMSK寄存器各位标记该位对应中断是否可用,0表示有效,1表示禁止。初始值都为1,即禁止所有中断。
PRIORITY寄存器用于设置6个中断优先权仲裁模块的工作方式,主要用来设定各中断优先策略。
INTPND寄存器的32位同一时刻最多只允许有一个值为1,这一位是有相就的中断请求发生,且该中断未被屏蔽,而且该中断请求通过了优先仲裁。这个中断请求将被送到CPU,CPU将跳转到中断服务程序执行。中断服务程序可以读取INTPND或INTOFFSET寄存器(当INTPND中某位标记中断请求发生了,INTOFFSET寄存器中的值为0-31,标记INTPND的哪一位被置为1了)的值,以确定哪个中断发生了。
有的几个中断共有一个SRCPND的中断位,比如INT_AC97和INT_WDT共用INT_WDT_AC97中断位。这种子中断共15个。子中断发生时,先在INTSRCPND寄存器相应位置1,如果INTSUBMSK寄存器相应位未屏蔽(即该位为0),则该中断送到SRCPND寄存器。
23个外部中断:
EINTINT0-2三个寄存器用于设置23个外部中断的触发方式和过滤器是否有效。触发方式有低电平、高电平、下降沿、上升沿、电平高低变化。
EINTFLT0-3三个寄存器用于设置外部中断引脚的过滤参数。
EINTMASK寄存器用于设置23个外部中断的屏蔽情况,默认是禁用中断的。
EINTPEND寄存器记录着23个外部中断哪一个发生了。发生中断的对应位置1。初始值为0。但清除中断位标记时要写入1。
进入和退出IRQ、保存和恢复环境代码:
HandleIRQ:
sub lr, lr, #4 @ 计算返回地址
stmdb sp!, { r0-r12,lr } @ 保存使用到的寄存器
@ 注意,此时的sp是中断模式的sp
@ 初始值是上面设置的4096
ldr lr, =int_return @ 设置调用IRQ_Handle函数后的返回地址
ldr pc, =IRQ_Handle @ 调用中断分发函数,在interrupt.c中
int_return:
ldmia sp!, { r0-r12,pc }^ @ 中断返回, ^表示将spsr的值复制到cpsr
中断服务代码示例:
/*interrupt registes*/
#define SRCPND (*(volatile unsigned long *)0x4A000000)
#define INTMOD (*(volatile unsigned long *)0x4A000004)
#define INTMSK (*(volatile unsigned long *)0x4A000008)
#define PRIORITY (*(volatile unsigned long *)0x4A00000c)
#define INTPND (*(volatile unsigned long *)0x4A000010)
#define INTOFFSET (*(volatile unsigned long *)0x4A000014)
#define SUBSRCPND (*(volatile unsigned long *)0x4A000018)
#define INTSUBMSK (*(volatile unsigned long *)0x4A00001c)
/*external interrupt registers*/
#define EINTMASK (*(volatile unsigned long *)0x560000a4)
#define EINTPEND (*(volatile unsigned long *)0x560000a8)
#define BIT_ALLMSK (0xffffffff)
//声明50个中断服务函数指针
void (*isr_handle_array[50])(void);
//虚拟中断服务
void Dummy_isr(void)
{
while(1);
}
//初始化中断
void init_irq(void)
{
int i = 0;
for (i = 0; i < sizeof(isr_handle_array) / sizeof(isr_handle_array[0]); i++)
{
isr_handle_array[i] = Dummy_isr;
}
INTMOD = 0x0; // 所有中断都设为IRQ模式
INTMSK = BIT_ALLMSK; // 先屏蔽所有中断
}
//中断处理
void IRQ_Handle(void)
{
unsigned long oft = INTOFFSET;
//清中断
if (oft == 4)
EINTPEND = 1<<7; //EINT4-7合用IRQ4,注意EINTPEND[3:0]保留未用,向这些位写入1可能导致未知结果
SRCPND = 1<
/* 调用中断服务程序 */
isr_handle_array[oft]();
}