Tiny6410裸机按键中断

本文介绍了Tiny6410芯片在裸机环境下如何处理按键中断,重点讲解了外部中断INT_EINT0和INT_EINT1的使用,以及向量中断和非向量中断的区别。在向量中断模式下,通过设置VE=1,利用VICXVECTADDR寄存器实现中断服务函数的自动跳转。中断初始化和中断服务函数的设计中,强调了保护和恢复现场的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、按键中断简介

裸机按键中断用到了外部中断:外部中断占了4个中断源(INT_EINT0  INT_EINT1   INT_EINT2  INT_EINT3  INT_EINT4)如下图所示

上传到服务器

在用到外部中断时需要知道所用的按键GPIO引脚属于哪一个中断源或者属于哪一个组,Tiny6410按键用到了GPN0~GPN5 六个引脚,其中GPN0~GPN3 属于INT_EINT0, GPN4和GPN5属于INT_EINT1  。

二、向量中断与非向量中断简介

IRQ中断发生后,PC值根据VE值的不同而跳转到不同的地方执行中断服务函数

当VE=0时,PC跳转至0x18处执行中断服务函数

当VE=1时,PC跳转至对应的VICXVECTADDR指定的函数入口地址执行中断服务函数

具体的VE这一位在协处理器CP15的寄存器C1中,对应C1的第24位,设置VE=1可以用以下汇编语句:

  mrc p15,0,r0,c1,c0,0  //将 CP15 的寄存器 C1 的值读到 r0 中

  orr r0,r0,#(1<<24)"   // 设置r0中的第24位为1

    mcr p15,0,r0,c1,c0,0  //将 r0 的值写到 CP15 的寄存器 C1 中

本文主要讲VE=1时的程序设计。

二、start.S 文件

.global _start
_start:

reset:
	// 把外设基地址告诉CPU
	ldr r0, =0x70000000   // 6410内存地址0~0x60000000 外设地址0x70000000 ~ 0x7fffffff
	orr r0,r0,#0x13       // 外设地址大小256M
	mcr p15,0,r0,c15,c2,4 // 把r0的值(外设基地址和外设大小)写给CPU
			      // mcr:ARM寄存器到协处理寄存器的数据传送指令
			      // mrc:协处理寄存器到ARM寄存器的数据传送指令
	// 关闭看门狗
	ldr r0, =0x7E004000
	mov r1, #0
	str r1, [r0]

	// 设置栈
	ldr sp, =0x0c002000


	//设置时钟
	bl clock_init
	bl irq_init
	// 开中断
	mrc p15,0,r0,c1,c0,0
	orr r0,r0,#(1<<24)   //这一块开中断和设置VE=1很重要
	mcr p15,0,r0,c1,c0,0
	mov r0, #0x53			
	msr CPSR_cxsf, r0
	//main函数
	ldr pc, =main

halt:
	b halt

使用VE=1的好处:在start.S中不涉及任何有关的中断函数跳转,而将中断函数的调转交给了VICXVECTADDR寄存器(当发生中断时,PC自动跳转至寄存器中的函数入口地址处执行对应的中断服务函数)

三、外部中断初始化及中断服务函数

中断初始化:

void irq_init(void)
{
	/* 配置GPN0~5引脚为中断功能 */
	GPNCON &= ~(0xfff);
	GPNCON |= 0xaaa;

	/* 设置中断触发方式为: 上升沿触发 */
	EINT0CON0 &= ~(0xfff);
	EINT0CON0 |= 0x444;
	/* 设置延时滤波寄存器*/
	EINT0FLTCON = 0x00ffffff;

	/* 禁止屏蔽中断 */
	EINT0MASK &= ~(0x3f);

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

	/* 注册中断处理函数*/
	VIC0VECTADDR0 = (unsigned long)eint_irq; //  INT_EINT0中断
	VIC0VECTADDR1 = (unsigned long)eint_irq; //  INT_EINT1中断
}

中断服务函数:中断服务函数需要加入保护现场和恢复现场的操作

//为了简便操作  六个按键(2个中断源)的中断服务函数的都相同
//中断服务函数执行led翻转操作
void eint_irq(void)
{
    //保护现场
    __asm__( 			    
	"sub lr, lr, #4\n"  
	"stmfd sp!, {r0-r12, lr}\n"       
	: 
	: 
			);	
	LedTriggle(); // 这是一个led翻转函数
	/* 清中断 */
	EINT0PEND   = 0x3f;
	VIC0ADDRESS = 0;
    //恢复现场
    __asm__( 
	"ldmfd sp!, {r0-r12, pc}^ \n"       
	: 
	: 
			);
}

以上为VE=1时的一些主要操作与下边内容没有任何关系。

四、对VE=0 时的非向量中断的一些理解

当VE=0时,PC会跳转至0x18处执行中断服务函数,所以需要在0x18处编写要执行的中断服务函数,具体在start.s中的实现如下:

.global _start
_start:
	// 异常向量表
	b reset               /* 复位时,cpu跳到0地址0x00 */
	b halt  	      /* cpu遇到不能识别的指令时 0x04*/
	b halt                /* swi异常,进入svc模式 0x08*/
	b halt		      /* 预取中止异常0x0b */
	b halt     	      /* 数据访问异常 0x10*/
	b halt  	      /* 没用到 0x14*/
	b irq          	      /* 中断异常 0x18*/
	b halt     	      /* 快中断异常 0x1b*/

reset:
	// 外设地址告诉cpu
    ldr r0, =0x70000000
    orr r0, r0, #0x13
    mcr p15,0,r0,c15,c2,4
    
	// 关看门狗
	ldr r0, =0x7E004000
	mov r1, #0
	str r1, [r0]
	
	// 设置栈
	ldr sp, =8*1024

	// 初始化时钟
	bl clock_init

	// 初始化ddr
	bl sdram_init

	// 初始化nandflash
	bl nand_init

	// 初始化irq
	bl irq_init

	// 开中断
	mov r0, #0x53			
	msr CPSR_cxsf, r0
on_ddr:
	// 跳转
	ldr pc, =main

	// 中断异常
irq:
	/* 保存现场 */
	ldr sp, =0x54000000				
	sub lr, lr, #4
	stmdb sp!, {r0-r12, lr}  
	/* 处理异常 */
	bl do_irq
	/* 恢复现场 */
	ldmia sp!, {r0-r12, pc}^  /* ^表示把spsr恢复到cpsr */
	
halt:
	b halt

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值