中断处理

BL

BL

    当执行BL指令时,指令执行过程中处理器内部就会将PC寄存器的值拷贝到

    LR寄存器,然后再将LR寄存器中的值自减4, 所以LR寄存器中保存的就是

    BL指令下一条指令的地址

 该时刻PC=N+8 LR=N+4

IRQ中断

IRQ中断

    当执行一条指令时产生了一个IRQ中断,执行这条指令过程中处理器不会保

    存返回地址,而是执行完成后才会保存,但执行完成后PC的值又会自动增4,

    所以对于IRQ来说LR中保存的是被中断打断的指令的下下条指令的地址

该时刻PC=N+12 LR=N+8
因此,产生irq中断时,CPU存储的的LR寄存器中的地址不对,需要认为减去0x4

汇编

.text
.global _start
_start:
	/*
	 * Vector table
	 */ 
	b reset
	b .
	b .
	b .
	b .
	b .
	b irq_handler
	b .

reset:
	/*
	 * Set vector address in CP15 VBAR register
	 */ 
	ldr	r0, =_start
	mcr	p15, 0, r0, c12, c0, 0	@Set VBAR

	/*
	 * Set the cpu to SVC32 mode, Disable FIQ/IRQ
	 */  
	mrs r0, cpsr
	bic r0, r0, #0x1f
	orr	r0, r0, #0xd3
	msr	cpsr ,r0

	/*
	 * Defines access permissions for each coprocessor
	 */  
    mov	r0, #0xfffffff
    mcr	p15, 0, r0, c1, c0, 2  	

	/*
	 * Invalidate L1 I/D                                                                                                                   
	 */
	mov	r0, #0					@Set up for MCR
	mcr	p15, 0, r0, c8, c7, 0	@Invalidate TLBs
	mcr	p15, 0, r0, c7, c5, 0	@Invalidate icache
	
	/*
	 * Set the FPEXC EN bit to enable the FPU
	 */ 
	mov r3, #0x40000000
	fmxr FPEXC, r3
	
	/*
	 * Disable MMU stuff and caches
	 */
	mrc	p15, 0, r0, c1, c0, 0
	bic	r0, r0, #0x00002000		@Clear bits 13 (--V-)
	bic	r0, r0, #0x00000007		@Clear bits 2:0 (-CAM)
	orr	r0, r0, #0x00001000		@Set bit 12 (---I) Icache
	orr	r0, r0, #0x00000002		@Set bit 1 (--A-) Align
	orr	r0, r0, #0x00000800		@Set bit 11 (Z---) BTB
	mcr	p15, 0, r0, c1, c0, 0

	/*
	 * Initialize stacks                                                                                                                  
	 */
init_stack:     
	/*svc mode stack*/
	msr cpsr, #0xd3
	ldr sp, _stack_svc_end

	/*undef mode stack*/
	msr cpsr, #0xdb
	ldr sp, _stack_und_end

	/*abort mode stack*/	
	msr cpsr,#0xd7
	ldr sp,_stack_abt_end

	/*irq mode stack*/	
	msr cpsr,#0xd2
	ldr sp, _stack_irq_end
	
	/*fiq mode stack*/
	msr cpsr,#0xd1
	ldr sp, _stack_fiq_end
	
	/*user mode stack, enable FIQ/IRQ*/
	msr cpsr,#0x10
	ldr sp, _stack_usr_end

	/*Call main*/
	b main
	irq_handler:
//修正返回地址
/*因为产生IRQ异常后自动保存的LR中的返回地址是被irq打断指令的
	下一条再下一条指令的地址,所以需要人为的去修复一下*/
	sub lr,lr,#4


	//因为IRQ模式下使用的R0-R12寄存器和user模式下使用的是同一组
	//所以在处理异常之前需要将之前的user模式下中寄存器的值压栈保护
	stmfd sp!,{r0-r12,lr}

	//处理异常
	bl do_irq

	//异常返回
	/*1.将r0-r12寄存器中的值出栈,使其恢复到异常打断之前的值
	  2.将spsr寄存器中的值恢复给cpsr,使CPU的状态恢复到被异常打断之前的状态*/

    // 3.将栈中的LR寄存器中的值出栈给pc,实现程序的返回 lr----->pc   程序返回

	ldmfd sp!,{r0-r12,pc}^  
	//  ^表示出栈的同时spsr的值回复给了cpsr中


_stack_svc_end:      
	.word stack_svc + 512
_stack_und_end:      
	.word stack_und + 512
_stack_abt_end:      
	.word stack_abt + 512
_stack_irq_end:      
    .word stack_irq + 512
_stack_fiq_end:
    .word stack_fiq + 512
_stack_usr_end:      
    .word stack_usr + 512

.data
stack_svc:      
	.space 512
stack_und:
	.space 512
stack_abt:      
	.space 512
stack_irq:      
	.space 512
stack_fiq:      
	.space 512
stack_usr:      
	.space 512

C程序

#include"exynos_4412.h"

void Delay (unsigned int Time )
{
	while(Time--);
}

int main()
{
	/*产生一个中断信号*/
	/*1.属于外设层次,让外部的硬件控制器能产生一个中断信号并发送给中断控制器*/



	/*将GPX1_1设置成中断功能*/
     GPX1.CON = GPX1.CON |( 0xF << 4);
	/*设置GPX1_1中断的触发方式---下降沿触发*/
   EXT_INT41_CON = EXT_INT41_CON & (~(0x7<<4))|(0x2<<4);
	/*使能GPX1_1的中断功能*/

   EXT_INT41_MASK = EXT_INT41_MASK & (~(1<<1));

  /*2.中断控制器层次--让中断控制器接收外设发来的中断信号并对其进行管理然后转发给合适的CPU去处理*/

   ICDDCR = ICDDCR |1;/*全局使能中断控制器,使其能够接收外部设备产生的中断信号并转发给CPU接口*/

    ICDISER.ICDISER1 = ICDISER.ICDISER1 | (1 <<25);
	/*在中断控制器中使能57号中断,使其中断控制器在接收到57号中断后能将其进一步转发到CPU接口*/
	ICDIPTR.ICDIPTR14 = ICDIPTR.ICDIPTR14 & (~ (0xFF<<8)) |(0x01<<8);
	/*选择cpu0来处理57号中断*/

	CPU0.ICCICR = CPU0.ICCICR | 1;
	/*将中断控制器和CPU0之间的接口使能,使得中断控制器转发的信号能够到达CPU0*/

      GPX2.CON  =GPX2.CON &( ~ (0xF <<28)) | (0x1 << 28);

	  while(1)
	  {
   		  GPX2.DAT = GPX2.DAT | (1<<7);

		  Delay(1000000);

		  GPX2.DAT = GPX2.DAT &( ~(1<<7));

		  Delay(1000000);
	  }

	return 0;
}

排队寄存器,结束中断处理程序:

区分是那种irq异常源的代码:(共160种中断)

//IRQ异常处理
void do_irq(void)
{
	unsigned int IrqNum = 0;
	/*从中断控制器中获取当前中断的中断号*/
	IrqNum = CPU0.ICCIAR & 0x3FF;
	
	/*根据中断号处理不同的中断*/
	switch(IrqNum)
	{
		case 0:
			//0号中断的处理程序
			break;
		case 1:
			//1号中断的处理程序
			break;
			/*
			 * ... ...
			 */
		case 57:
			printf("Key2 Pressed\n");
			/*清除GPIO控制器中GPX1_1的中断挂起标志位*/
			EXT_INT41_PEND = (1 << 1);
			/*将当前中断的中断号写回到中断控制器中,以这种方式来告知中断控制器当前的中断已经处理完成,可以发送其它中断*/
			CPU0.ICCEOIR = CPU0.ICCEOIR & (~(0x3FF)) | (57);
			break;
			/*
			 * ... ...
			 */
		case 159:
			//159号中断的处理程序
			break;
		default:
			break;
	}

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值