[国嵌攻略][050][2440按键中断编程]

程序结构优化

1.把不同的功能放到不同的文件里面

2.一般在bootloader中不使用MMU,所以关掉MMU

 

按键初始化

1.打开开发板的原理图,找到按键

2.把对应的GPIO配置成中断,对中断源进行初始化

 

初始化中断控制器

1.SUBMASK和MASK必须要保证没有屏蔽中断,GPIO是不属于子中断,所以不用设置SUBMASK,MODE和Priority保存默认值即可,设置INTMSK(0x4A000008)

2.EINT4_7对应4个中断,分开设置需要设置EINTMASK(0x560000A4)。注意,设置EINTMASK寄存器必须要在INTMASK之前设置

3.在核心预处理时,关闭了中断,在这里需要打开中断

 

中断处理

1.当中断产生时,会跳转到中断向量表,执行ldr pc, _irq

 

2.保存环境

2.1.当前lr指向pc+8的位置,当中断返回时需要返回到lr-4的位置,算出lr的值,sub lr, lr, #4

2.2.保存寄存器到堆栈,stmfd sp!, {r0-r12, lr}

2.3.调用中断处理函数,handle_int

2.4.从堆栈恢复寄存器,ldmfd sp!, {r0-r12, pc}^

2.5.handle_int需要做:1.判断中断源 2.根据中断源,执行不同的中断处理。INTOFFSET(0x4A000014)标明了那个中断源产生了中断

 

3.清除中断,在恢复环境之前先要清除SRCPND(0x4A000000)和INTPND(0x4A000010)对应位的请求,保证下次中断能被处理。如果下次中断到来,发现SRCPND和INTPND对应位为1,表示上次中断还没有被处理,忽略这次中断请求。如果用到是子中断需要清零SUBSRCPND,如果用到的是EINT4-ENT23那么要清除EINTPEND(0x560000A8)。注意,要清除中断时要往对应位上写入1

 

4.注意在irq模式中设置的sp栈指针是r13_irq,而初始化栈sp指针是r13_svc。所以在初始化栈指针是要对r13_irq和r13_svc都要设置地址

/********************************************************************
*名称:irq
*功能:中断处理
*********************************************************************/
irq:
	//保存环境
	sub lr, lr, #4            //三级流水线,pc指向指定的地址与当前执行指令的地址偏移+8
	stmfd sp!, {r0-r12, lr}   //保存r0-r12和lr寄存器的值到栈中
	
	//处理中断
	bl process_int
	
	//恢复环境
	ldmfd sp!, {r0-r12, pc}^   //从栈中载入r0-r12和lr寄存器的值,^表示把spsr恢复到cpsr

 

/********************************************************************
*名称:int
*作者:D
*时间:2015.11.10
*功能:中断控制器
********************************************************************/

/********************************************************************
*							 宏定义
********************************************************************/
#define SRCPND 0X4A000000     //中断源请求寄存器
#define INTPND 0X4A000010     //中断请求寄存器
#define INTMSK 0x4A000008     //中断掩码寄存器
#define EINTMASK 0x560000A4   //外部中断掩码寄存器
#define EINTPEND 0x560000A8   //外部中断请求寄存器

.text
/********************************************************************
*名称:init_int
*功能:初始化中断
*********************************************************************/
.global init_int
init_int:
	//屏蔽中断
	ldr r0, =INTMSK
	mvn r1, #0   //屏蔽中断,设置INTMSK[31-0]:0xFFFFFFFF
	str r1, [r0]
	
	//关闭中断
	mrs r0, cpsr
	orr r0, r0, #0x000000C0   //关闭中断,设置cpsr[7-6]:11
	msr cpsr, r0
	
	mov pc, lr
	
/********************************************************************
*名称:enable_int
*功能:打开中断
*********************************************************************/
.global enable_int
enable_int:
	//使能中断
	ldr r0, =EINTMASK
	ldr r1, [r0]
	bic r1, r1, #0x00000900   //使能外部中断,设置外部中断掩码EINT8:0 EINT11:0
	str r1, [r0]
	
	ldr r0, =INTMSK
	ldr r1, [r0]
	bic r1, r1, #0x00000020   //使能中断,设置中断掩码EINT8_23:0
	str r1, [r0]
	
	//打开中断
	mrs r0, cpsr
	bic r0, r0, #0x000000C0   //打开中断,设置cpsr[7-6]:00
	msr cpsr, r0
	
	mov pc, lr
	
/********************************************************************
*名称:process_int
*功能:处理中断
*********************************************************************/
.global process_int
process_int:
	mov ip, lr   //保存链接寄存器,嵌套调用保存返回地址
	
	//读取中断源
	ldr r0, =EINTPEND   //读取外部中断请求,如果中断从INTOFFSET中读取,子中断从SUBSRCPND
	ldr r1, [r0]
	
	//处理中断源
	cmp r1, #0x00000100   //如果是EINT8,调用EINT8中断处理
	beq eint8_process
	cmp r1, #0x00000800   //如果是EINT11,调用EINT11中断处理
	beq eint11_process
	b end_process_int     //如果都不是,结束中断处理
	
eint8_process:
	bl on_led    //点亮led
	b end_process_int
	
eint11_process:
	bl off_led   //熄灭led
	b end_process_int

end_process_int:
	//清除中断源
	ldr r0, =EINTPEND
	ldr r1, [r0]
	str r1, [r0]              //清除外部中断请求
	
	ldr r0, =SRCPND
	ldr r1, [r0]
	orr r1, r1, #0x00000020   //清除中断源请求,设置EINT8_23:0,如果是子中断还要清除SUBSRCPND
	str r1, [r0]
	
	ldr r0, =INTPND
	ldr r1, [r0]
	orr r1, r1, #0x00000020   //清除中断请求,设置EINT8_23:0
	str r1, [r0]
	
	mov lr, ip   //恢复链接寄存器,嵌套调用恢复返回地址
	mov pc, lr

 

注意:在函数嵌套调用中要先把lr保存到ip中,在函数中被调用其他函数时会改变,当外部函数返回时,需要从ip中恢复lr,用于返回到外部函数被调用处

 

r0-r15寄存器作用

r0-r3

用作传入函数参数,传出函数返回值。在子程序调用之间,可以将 r0-r3 用于任何用途。被调用函数在返回之前不必恢复 r0-r3。如果调用函数需要再次使用 r0-r3 的内容,则它必须保留这些内容。

r4-r11

被用来存放函数的局部变量。如果被调用函数使用了这些寄存器,它在返回之前必须恢复这些寄存器的值。

r12

是内部调用暂时寄存器 ip。它在过程链接胶合代码(例如,交互操作胶合代码)中用于此角色。在过程调用之间,可以将它用于任何用途。被调用函数在返回之前不必恢复 r12。

r13

是栈指针 sp。它不能用于任何其它用途。sp 中存放的值在退出被调用函数时必须与进入时的值相同。

r14

是链接寄存器 lr。如果您保存了返回地址,则可以在调用之间将 r14 用于其它用途,程序返回时要恢复

r15

是程序计数器 PC。它不能用于任何其它用途。

注意:在中断程序中,所有的寄存器都必须保护,编译器会自动保护R4~R11

posted @ 2015-11-11 10:26  盛夏夜  阅读(269)  评论(0编辑  收藏  举报