6410之向量中断

向量中断:

在分辨是哪个中断的时候非常有用,6410中64组中断,就可以使用向量中断来进行判断。


以前31组中断为例,假如Vectored interrupt 1发生了中断,它就会将Vectored interrup 1的地址告诉VectorAddr寄存器。如下图所示:


6410中有两个中断控制器,它们分别为VIC0,VIC1,假如VIC0的第0组中断源发生了中断,硬件上,6410就会把VIC0VECTADDR0赋值给VIC0ADDRESS,其中VIC0VECTADDR0对应于中断处理函数的地址。当某一组中断发生后,CPU就会自动分辨是哪个中断,从而进行处理相应的处理函数。

注意:向量中断只能分辨是哪一组,具体是其中一组的哪个中断,还需要继续进行细分。


程序代码:

.globl _start
_start:

	/* 0 地址 */
	b reset                 /* 复位时,cpu跳到0地址 */
	ldr pc, =undefined_instruction  /* cpu遇到不能识别的指令时 */
	ldr pc, _vector_swi             /* 当执行swi指令时, 进入swi模 式 */
	b halt     @ldr	pc, _prefetch_abort /* 预取中止异常 */
	b halt     @ldr	pc, _data_abort     /* 数据访问异常 */
	b halt     @ldr	pc, _not_used       /* 没用到 */
	ldr	pc, _irq            /* 0x18 中断异常 */
	b halt     @ldr	pc, _fiq            /* 快中断异常 */

_irq :
	.word vector_irq          /*向量中断处理*/

_vector_swi:
	.word vector_swi
		
vector_swi:
	/* 1. 保存现场 */
	ldr sp, =0x56000000
	stmdb sp!, {r0-r12, lr}  /* lr就是swi的下一条指令地址 */

	/* 2. 处理异常 */
	mrs r0, cpsr
	ldr r1, =swi_str
	bl print_cpsr

	/* 3. 恢复现场 */
	ldmia sp!, {r0-r12, pc}^ /* ^表示把spsr恢复到cpsr */
	
swi_str:
	.word 0x00697773  /* swi */
	
undefined_instruction:
	/* 1. 保存现场 */
	ldr sp, =0x55000000
	stmdb sp!, {r0-r12, lr}

	/* 2. 处理异常 */
	mrs r0, cpsr
	ldr r1, =und_str
	bl print_cpsr

	/* 3. 恢复现场 */
	ldmia sp!, {r0-r12, pc}^  /* ^表示把spsr恢复到cpsr */

und_str:
	.word 0x00646e75  /* und */

usr_str:
	.word 0x00727375  /* usr */


vector_irq:
	/* 1. 保存现场 */
	ldr sp, =0x54000000
	sub lr, lr, #4
	stmdb sp!, {r0-r12, lr}  /* lr就是swi的下一条指令地址 */

	/* 2. 处理异常 */
	bl do_irq
	
	/* 3. 恢复现场 */
	ldmia sp!, {r0-r12, pc}^  /* ^表示把spsr恢复到cpsr */

reset:
/* 硬件相关的设置 */
    /* Peri port setup */
    ldr r0, =0x70000000
    orr r0, r0, #0x13
    mcr p15,0,r0,c15,c2,4       @ 256M(0x70000000-0x7fffffff)
    
/* 关看门狗 */
/* 往WTCON(0x7E004000)写0 */
	
	ldr r0, =0x7E004000
	mov r1, #0
	str r1, [r0]
	
	/* 设置栈 */
	ldr sp, =8*1024

	/* 设置时钟 */
	bl clock_init
	bl ddr_init
	bl init_uart

/* 把程序的代码段、数据段复制到它的链接地址去 */	
	adr r0, _start   /* 获得_start指令当前所在的地址 : 0*/
	ldr r1, =_start  /* _start的链接地址 0x51000000 */
	
	ldr r2, =bss_start      /* bss段的起始链接地址 */
	
	sub r2, r2, r1
	
	cmp r0,r1
	beq clean_bss
	
	bl copy2ddr
	cmp r0, #0
	bne halt
		
	/* 清BSS */
/* 把BSS段对应的内存清零 */
clean_bss:
	ldr r0, =bss_start
	ldr r1, =bss_end
	mov r3, #0
	cmp r0, r1
	ldreq pc, =on_ddr
clean_loop:
	str r3, [r0], #4
	cmp r0, r1	
	bne clean_loop		
	ldr pc, =on_ddr

on_ddr:	

	bl irq_init

	mrs r0, cpsr
	bic	r0,r0,#0x9f  /* 清cpsr的I位,M4~M0 */
	orr	r0,r0,#0x10
	msr	cpsr,r0      /* 进入user mode */

	ldr sp, =0x57000000

	ldr r1, =usr_str
	bl print_cpsr
	
	swi 0    /*
	          * cpu进入svc模式
	          * 把之前的cpsr保存到spsr_svc 
	          * 切换到r13_svc, r14_svc
	          * 把swi的下一条指令存到r14(lr)_svc
	          * 跳到地址8
	          */
	bl hello
undef:
	.word 0xff000000 /*
			          * cpu进入Undefined模式
			          * 把之前的cpsr保存到spsr_und 
			          * 切换到r13_und, r14_und
			          * 把下一条指令存到r14(lr)_und
			          * 跳到地址4
			          */
	
swi_ret:
	bl main
	

halt:
	b halt	

向量中断初始化以及相关处理:

#define GPNCON     (*((volatile unsigned long *)0x7F008830))
#define GPNDAT     (*((volatile unsigned long *)0x7F008834))

#define EINT0CON0  (*((volatile unsigned long *)0x7F008900))
#define EINT0MASK  (*((volatile unsigned long *)0x7F008920))

#define EINT0PEND  (*((volatile unsigned long *)0x7F008924))

#define PRIORITY    (*((volatile unsigned long *)0x7F008280))
#define SERVICE     (*((volatile unsigned long *)0x7F008284))
#define SERVICEPEND (*((volatile unsigned long *)0x7F008288))


#define VIC0IRQSTATUS  (*((volatile unsigned long *)0x71200000))
#define VIC0FIQSTATUS  (*((volatile unsigned long *)0x71200004))
#define VIC0RAWINTR    (*((volatile unsigned long *)0x71200008))
#define VIC0INTSELECT  (*((volatile unsigned long *)0x7120000c))
#define VIC0INTENABLE  (*((volatile unsigned long *)0x71200010))
#define VIC0INTENCLEAR (*((volatile unsigned long *)0x71200014))
#define VIC0PROTECTION (*((volatile unsigned long *)0x71200020))
#define VIC0SWPRIORITYMASK (*((volatile unsigned long *)0x71200024))
#define VIC0PRIORITYDAISY  (*((volatile unsigned long *)0x71200028))

#define VIC0VECTADDR0      (*((volatile unsigned long *)0x71200100))
#define VIC0VECTADDR1      (*((volatile unsigned long *)0x71200104))
#define VIC0ADDRESS        (*((volatile unsigned long *)0x71200f00))

void eint0_3_irq(void)//对第0组中断的处理
{
	int i;
	
	printf("eint0_3_irq\n\r");  /* K1~K4 */
	for (i = 0; i < 4; i ++)
	{
		if (EINT0PEND & (1<<i))
		{
			if (GPNDAT & (1<<i))
			{
				printf("K%d released\n\r", i+1);
			}
			else
			{
				printf("K%d pressed\n\r", i+1);
			}
		}
	}

}

void eint4_11_irq(void)//对第一组中断的处理
{
	int i;
	printf("eint4_11_irq\n\r"); /* K5~K6 */
	for (i = 4; i < 6; i ++)
	{
		if (EINT0PEND & (1<<i))
		{
			if (GPNDAT & (1<<i))
			{
				printf("K%d released\n\r", i+1);
			}
			else
			{
				printf("K%d pressed\n\r", i+1);
			}
		}
	}

}


void irq_init(void)//向量中断初始化
{
	/* 配置GPIO引脚为中断引脚 */
	/* GPN0~5 设为中断引脚 */
	GPNCON &= ~(0xfff);
	GPNCON |= 0xaaa;

	/* 设置中断触发方式为: 双边沿触发 */
	EINT0CON0 &= ~(0xfff);
	EINT0CON0 |= 0x777;

	/* 使能中断 */
	EINT0MASK &= ~(0x3f);

	/* 在中断控制器里使能这些中断 */
	VIC0INTENABLE |= (0x3); /* bit0: eint0~3, bit1: eint4~11 */ 

	VIC0VECTADDR0 = eint0_3_irq;    //直接向向量中断处理函数赋值给VIC0VECTADDR0,硬件上VIC0VECTADDR0会自动赋值给VIC0ADDRESS
	VIC0VECTADDR1 = eint4_11_irq;

	/* 设置优先级 */
}


void do_irq(void)
{
	int i = 0;

	void (*the_isr)(void);//函数指针

	the_isr = VIC0ADDRESS;//将VIC0ADDRESS赋值给函数指针,就是将相关的中断处理函数赋值给它
		
	/* 2.1 分辨是哪个中断 */
	/* 2.2 调用它的处理函数 */	
	/* 2.3 清中断 */	

	the_isr();//处理中断
	
	EINT0PEND   = 0x3f;  /* 清中断 */
	VIC0ADDRESS = 0;
}





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值