006_mini2440裸机异常和中断

6 篇文章 0 订阅
6 篇文章 0 订阅

006_mini2440裸机异常和中断

基于ARM920T的S3C2440的7种操作模式

1、User (usr): The normal ARM program execution state
2、 FIQ (fiq): Designed to support a data transfer or channel process
3、 IRQ (irq): Used for general-purpose interrupt handling
4、 Supervisor (svc): Protected mode for the operating system
5、 Abort mode (abt): Entered after a data or instruction prefetch abort
6、 System (sys): A privileged user mode for the operating system
7、 Undefined (und): Entered when an undefined instruction is executed

操作模式介绍

1、FIQ
The FIQ (Fast Interrupt Request) exception is designed to support a data transfer or channel process, and in ARM state has sufficient private registers to remove the need for register saving (thus minimizing the overhead of context switching).
Irrespective of whether the exception was entered from ARM or Thumb state, a FIQ handler should leave the interrupt by executing SUBS PC,R14_fiq,#4
2、IRQ
The IRQ (Interrupt Request) exception is a normal interrupt caused by a LOW level on the nIRQ input. IRQ has a lower priority than FIQ and is masked out when a FIQ sequence is entered. It may be disabled at any time by setting I bit in the CPSR, though this can only be done from a privileged (non-User) mode.
Irrespective of whether the exception was entered from ARM or Thumb state, an IRQ handler should return from the interrupt by executing SUBS PC,R14_irq,#4.
3、Abort
An abort indicates that the current memory access cannot be completed. It can be signaled by the external ABORT input. ARM920T checks for the abort exception during memory access cycles.
4、Software Interrupt
The Software Interrupt Instruction (SWI) is used for entering Supervisor mode, usually to request a particular supervisor function. A SWI handler should return by executing the following irrespective of the state (ARM or Thumb): MOV PC,R14_svc.
5、Undefined Instruction
When ARM920T comes across an instruction which cannot be handled, it takes the undefined instruction trap. This mechanism may be used to extend either the THUMB or ARM instruction set by software emulation. After emulating the failed instruction, the trap handler should execute the following irrespective of the state (ARM or Thumb): MOVS PC,R14_und.

异常向量地址以及模式切换

下图所示为异常向量的地址以及异常发生时进入什么模式
例如:当系统复位时进入Supervisor模式,此时程序跳转到地址0开始执行程序

在这里插入图片描述

处理异常需要进行的操作

1、Preserves the address of the next instruction in the appropriate Link Register. If the exception has been entered from ARM state, then the address of the next instruction is copied into the Link Register (that is, current PC + 4 or PC + 8 depending on the exception.
2、Copies the CPSR( Current Program Status Register) into the appropriate SPSR(Saved Program Status Registers).
3、Forces the CPSR mode bits to a value which depends on the exception.
4、Forces the PC to fetch the next instruction from the relevant exception vector.

结束异常处理时需要进行的操作

1、Moves the Link Register, minus an offset where appropriate, to the PC. (The offset will vary depending on the type of exception.)
2、Copies the SPSR back to the CPSR.
3、Clears the interrupt disable flags, if they were set on entry.

未定义指令异常、软件中断异常

当代码运行遇到未定义指令时触发未定义指令异常,并跳到异常处理函数处通过串口打印输出cpsr寄存器的当前值。


.text					    /* .text部分是处理器开始执行代码的地方,指定了后续编译出来的内容放在代码段     */
    
.global _start			    /* .global关键字用来让一个符号对链接器可见,可以供其他链接对象模块使用		  					      */
	                        /* .global _start让_start符号成为可见的标识符,链接器才知道跳转到什么位置                          */ 

_start:
    	b reset          	/* vector 0    : Reset                 -> Supervisor      */
    	ldr pc, und_addr 	/* vector 4    : Undefined instruction -> Undefined       */
    	ldr pc, swi_addr 	/* vector 8    : Software Interrupt    -> Supervisor      */
    	b halt			 	/* vector 0x0c : Abort (prefetch)      -> Abort           */
    	b halt			 	/* vector 0x10 : Abort (data)          -> Abort 	      */
    	b halt			 	/* vector 0x14 : Reserved              -> Reserved		  */
    	ldr pc, irq_addr    /* vector 0x18 : Irq                   -> Irq 			  */
    	b halt			 	/* vector 0x1c : Fiq                   -> Fiq 			  */

und_addr:
	.word do_und            /* 在当前位置放一个word型的值,这个值就是do_und */

swi_addr:
	.word do_swi

irq_addr:
	.word do_irq

do_und:
	/****************************************************************
	 执行到这里之前:
	 * 1. lr_und保存有被中断模式中的下一条即将执行的指令的地址
	 * 2. SPSR_und保存有被中断模式的CPSR
	 * 3. CPSR中的M4-M0被设置为11011, 进入到und模式
	 * 4. 跳到0x4的地方执行程序 
	 ***************************************************************/

	
	ldr sp, =0x34000000				/* 设置堆栈 */

	/* 在und异常处理函数中有可能会修改r0-r12, 所以先保存 */
	/* lr是异常处理完后的返回地址, 也要保存                              */
	stmdb sp!, {r0-r12, lr}  
									/* 保存现场 					 */
									/* 处理und异常 					 */
	mrs r0, cpsr
	ldr r1, =und_string
	bl printException
									/* 恢复现场			    		 */
	ldmia sp!, {r0-r12, pc}^  		/* ^会把spsr的值恢复到cpsr里 */
	
und_string:
	.string "undefined instruction exception"

.align 4

do_swi:
	/************************************************************
	执行到这里之前:
	 * 1. lr_svc保存有被中断模式中的下一条即将执行的指令的地址
	 * 2. SPSR_svc保存有被中断模式的CPSR
	 * 3. CPSR中的M4-M0被设置为10011, 进入到svc模式
	 * 4. 跳到0x08的地方执行程序 
	 ************************************************************/

	/* sp_svc未设置, 先设置它									 */
	ldr sp, =0x33e00000

	/* 保存现场 											 */
	/* 在swi异常处理函数中有可能会修改r0-r12, 所以先保存 */
	/* lr是异常处理完后的返回地址, 也要保存 							 */
	stmdb sp!, {r0-r12, lr}  

	mov r4, lr
								  /* 处理swi异常 					*/
	mrs r0, cpsr
	ldr r1, =swi_string
	bl printException

	sub r0, r4, #4
	bl printSWIVal
								  /* 恢复现场 						*/
	ldmia sp!, {r0-r12, pc}^      /* ^会把spsr的值恢复到cpsr里 	        */
	
swi_string:
	.string "swi exception"

.align 4

do_irq:
	 /*********************************************************** 
	 * 执行到这里之前:
	 * 1. lr_irq保存有被中断模式中的下一条即将执行的指令的地址
	 * 2. SPSR_irq保存有被中断模式的CPSR
	 * 3. CPSR中的M4-M0被设置为10010, 进入到irq模式
	 * 4. 跳到0x18的地方执行程序 
	 ***********************************************************/

	/* sp_irq未设置, 先设置它 									 */
	 
	ldr sp, =0x33d00000

	/* 保存现场 											 */
	/* 在irq异常处理函数中有可能会修改r0-r12, 所以先保存 */
	/* lr-4是异常处理完后的返回地址, 也要保存 							 */
	sub lr, lr, #4
	stmdb sp!, {r0-r12, lr}  
	
	/* 处理irq异常 */
	bl handle_irq
								/* 恢复现场 						 */
	ldmia sp!, {r0-r12, pc}^  	/* ^会把spsr_irq的值恢复到cpsr里 */

reset:
	
	ldr r0, =0x53000000		/* 关闭看门狗 					     			 			*/
	ldr r1, =0
	str r1, [r0]
	
							/* 设置MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m  		*/
							/* LOCKTIME(0x4C000000) = 0xFFFFFFFF 				  	*/
	ldr r0, =0x4C000000
	ldr r1, =0xFFFFFFFF
	str r1, [r0]

							/* CLKDIVN(0x4C000014) = 0X5,tFCLK:tHCLK:tPCLK = 1:4:8	*/
	ldr r0, =0x4C000014
	ldr r1, =0x5
	str r1, [r0]

							/* 设置CPU工作于异步模式 										*/
	mrc p15,0,r0,c1,c0,0
	orr r0,r0,#0xc0000000   /* R1_nF:OR:R1_iA									    */
	mcr p15,0,r0,c1,c0,0
							/* 一旦设置PLL, 就会锁定lock time直到PLL输出稳定						*/
							/* 然后CPU工作于新的频率FCLK	 									*/
	ldr r0, =0x4C000004
	ldr r1, =(92<<12)|(1<<4)|(1<<0)
	str r1, [r0]

	/*********************************************************************
	 * 设置内存: sp 栈 
	 * 分辨是nor/nand启动
	 * 写0到0地址, 再读出来
	 * 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动
	 * 否则就是nor启动
	*********************************************************************/
	mov r1, #0
	ldr r0, [r1] 				/* 读出原来的值备份 							*/
	str r1, [r1] 				/* 0->[0] 								*/ 
	ldr r2, [r1] 				/* r2=[0] 								*/
	cmp r1, r2   				/* r1==r2? 如果相等表示是NAND启动 				*/
	ldr sp, =0x40000000+4096	/* 先假设是nor启动 							*/
	moveq sp, #4096  			/* nand启动 								*/
	streq r0, [r1]   			/* 恢复原来的值 								*/

	bl sdram_init
								/* 重定位text, rodata, data段整个程序 			*/
	bl copy2sdram
								/* 清除BSS段 								*/
	bl clean_bss

	/********************************************************************
	 * 复位之后, cpu处于svc模式
	 * 现在, 切换到usr模式
	 * MRS指令用于将程序状态寄存器的内容传送到通用寄存器中
	 * MSR指令用于将操作数的内容传送到程序状态寄存器的特定域中
	 *******************************************************************/
	mrs r0, cpsr         		/* 读出cpsr 								*/
	bic r0, r0, #0xf    		/* 修改M4-M0为0b10000, 进入usr模式 			*/
	bic r0, r0, #(1<<7)  		/* 清除I位, 使能中断 							*/
	msr cpsr, r0
								/* 设置 sp_usr 							*/
	ldr sp, =0x33f00000

	ldr pc, =uart
uart:
	bl uart0_init

	bl print1

	ldr pc, =und_code
						/* 故意加入一条未定义指令 									*/
und_code:
	.word 0xdeadc0de  	/* 未定义指令 										*/
	bl print2

	swi 0x123 			/* 执行此命令, 触发SWI异常, 进入0x8执行 						*/

	ldr pc, =main  		/* 绝对跳转, 跳到SDRAM 								*/

halt:
	b halt
	

按键中断异常

1、按键原理图
在这里插入图片描述
由上图可知四个按键分别挂载在EINT0、EINT2、EINT11、EINT19上,其对应的2440的I/O口如下:
在这里插入图片描述
2、按键中断初始化程序

/* 初始化按键为外部中断源 */

void key_eint_init(void)
{
	/* 1、 配置对应引脚为外部中断模式 */
	GPFCON &= ~((3 << 0) | (3 <<  4));             //对应位清零(GPF0、GPF2)
	GPFCON |=  ((2 << 0) | (2 <<  4));			   //设置对应引脚为外部中断模式
	
	GPGCON &= ~((3 << 6) | (3 << 22));            //对应位清零(GPG3、GPG11)
	GPGCON |=  ((2 << 6) | (2 << 22));			   //设置对应引脚为外部中断模式

	/* 2、 配置对应引脚为内部上拉模式 */
	GPFUP &= ~((1 << 0) | (1 <<  4));			   // S2 、S3
	GPGUP &= ~((1 << 6) | (1 << 22));			   // S4 、S5

	/* 3、 配置中断的双边沿触发方式                */
	EXTINT0 |=  ((7 << 0) | (7 <<  8));			   // S2 、S3
	EXTINT1 |=  (7 << 12);						   // S4
	EXTINT2 |=  (7 << 12);						   // S5

	/* 4、  配置外部中断屏蔽寄存器                */
	EINTMASK &= ~((1 << 11) | (1 << 19));	       //使能外部中断EINT11、EINT19

	/* 5、  初始化中断控制器                   */
	register_irq(0,key_eint_irq);
	register_irq(2,key_eint_irq);
	register_irq(5,key_eint_irq);
	//INTMSK &= ~((1 << 0) | (1 << 2) | (1 << 5));  //开启对应中断源的中断服务	
	
}

定时器中断异常


void timer_init(void)
{
	/**************************************************************************
	1、配置定时器的时钟
	Timer input clock Frequency = PCLK / {prescaler value+1} / {divider value}
	{prescaler value} = 0~255
	{divider value} = 2, 4, 8, 16
	2、设置计数缓冲寄存器(TCNTB0)即设置初值
	3、加载初值启动timer0
	4、设置自动加载
	5、在中断控制器中设置INTMSK相应位为1关闭中断屏蔽
	6、编写中断处理函数
	**************************************************************************/
	
	//1、设置时钟为50_000_000/100/16 = 31250
	TCFG0 &= ~0xffff;		//prescaler value = 99
	TCFG0 |= 99;		

	TCFG1 &= ~0xf;			//divider value = 16
	TCFG1 |= 3;

	//2、设置初值
	TCNTB0 = 15625;         //TCNTB0 = 15625 (0.5s)

	//3、加载初值启动timer0并配置自动重装载
	TCON |=  (1<<1);
	TCON &= ~((1<<0) | (1<<1) | (1<<2) | (1<<3));
	TCON |=  ((1<<0) | (0<<1) | (0<<2) | (1<<3));

	//4、设置INTMSK
	register_irq(10,timer_irq);
	//INTMSK &= ~(1<<10);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Da Liu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值