s3c2440异常与中断

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Utotao/article/details/88068642

1.s3c2440模式与状态

在阅读此文时候需要将上一篇博客完全搞懂。

1.1.模式

ARM一共有7种模式

 1. usr模式

用户模式是给写应用程序的人使用的,防止他们破坏操作系统。


 2. sys模式
 3. undefined模式
 4. svc管理模式
 5. abort中止模式:① 指令预取中止;② 数据访问中止
 6. IRQ中断模式
 7. FIQ快中断模式

这六种模式称为特权模式(privileged mode)在这6种模式之下,可任意切换到其它模式(通过编程操作cpsr寄存器直接进入到其他模式)。
此外,在linux中,不会使用FIQ模式。

1.2.CPU State

一共有两种state:

 1. ARM state:ARM指令集,每个指令占据4字节
 2. Thumb state:Thumb 指令集,每个指令占据2个字节

在嵌入式系统中,Nor Flash或者NAND Flash很大,不用节省这一点空间,所以使用ARM state即可。

1.3寄存器

1.3.1CPSR寄存器(程序状态寄存器)

CPSR寄存器:

CPSR程序状态寄存器
M[4:0]控制模式


T位:state bits(ARM state、Thumb state)

F位:FIQ disable,为1时所用的FIQ禁止

I位:IRQ disable,为1时,禁止所有IRQ

1.3.2.其余寄存器

CPSR
关于r0-r12的说明:

关于r13-r15的说明:

r13 : sp寄存器
r14:lr寄存器
r15:pc


2.异常处理流程

2.1.进入异常操作

程序进入异常是硬件所操作的

  1. 下一条指令的地址保存在lr寄存器中,以便恢复现场:LR_异常 = 下一条指令地址
  2. 把CPSR保存到spr_异常:SPSR_异常 = CPSR
  3. 修改cpsr的模式为进入异常
  4. 跳转到向量表(硬件完成

2.2.退出异常操作

  1. lr寄存器减去某个值赋值给pcpc = LR_异常 - offset
  2. 恢复CPSR的值:CPSR = SPCR_异常
  3. 清中断(其余异常不用管)


3.undefined异常处理实例

 1. 在start.S中配置异常向量表
 2. 配置响应函数
 3. 配置异常服务函数

①. 配置异常向量表

ARM异常向量表:
Exception Vector
配置中断向量代码:
这里两种配置方式:
<1>:
在这里插入图片描述
<2>:
在这里插入图片描述
两种配置方式本质是一样一样的,具体实现原理可以参考上一篇博客
:

②. 配置响应函数

中断向量响应

step1:设置新mode下的栈
只要这个栈地址不予其他模式下的栈地址重合就可以了

step2:保存现场
① 是否需要对lr值进行处理
例如对于irq模式,需要先将lr-4,在存入栈中
具体可以参考下表:
Exception Entry/Exit

② 保存r0-r12,lr

stmdb sp!,{r0-r12,lr} //先减后存

step3:中断服务函数

bl interrupt_service_function

step4:恢复现场

ldmia sp!,{r0-r12,pc}^	
/* 先读后加,^ 表示恢复`CPSR`的值:CPSR = SPCR_异常 */

③. 配置异常服务函数

使用c语言实现print_un即可

void print_un(void)
{
	putstr("\n\r");
	putstr("\n\r");
	putstr("\n\r");
	putstr("\n\rException:undefined!\n\r");
}


4.SWI(software interrupt)异常处理实例

 1. 在start.S中配置异常向量表
 2. 配置响应函数
 3. 配置异常服务函数

①. 配置异常向量表

②. 配置响应函数

③. 配置异常服务函数

所有过程参考以上undefined异常处理过程,几乎一毛一样



5.IRQ(外部中断)处理实例

5.1. 初始化设置

① 设置CPU,CPSR的I位,它是中断的总开关

在start.S中配置CPSR,清除其I位,打开总中断
打开总中断

② 设置中断源,让它能够发出中断信号

配置引脚为中断引脚
在这里插入图片描述

③ 设置外部中断源的触发方式

中断触发方式

④ 设置中断控制寄存器,让它能发出中断给CPU

使能外部中断屏蔽寄存器就可以了,即清除相对应的中断允许位
INTMSK寄存器

/* SRCPND 用来显示哪个中断产生了, 需要清除对应位
 * bit0-eint0
 * bit2-eint2
 * bit5-eint8_23
 */

/* INTMSK 用来屏蔽中断, 1-masked
 * bit0-eint0
 * bit2-eint2
 * bit5-eint8_23
 */

/* INTPND 用来显示当前优先级最高的、正在发生的中断, 需要清除对应位
 * bit0-eint0
 * bit2-eint2
 * bit5-eint8_23
 */

/* INTOFFSET : 用来显示INTPND中哪一位被设置为1
 */
/* 初始化中断控制器 */
void interrupt_init(void)
{
	INTMSK &= ~((1<<0) | (1<<2) | (1<<5)|(1<<10));//bit10:定时器0的中断
}

5.2. 响应中断,分辨中断源,对终端进行处理

5.3. 处理完要清除中断

分别清除:EINTPEND、SRCPND、INTPND



6.定时器中断

① 配置时钟

定时器时钟计算公式:
timer clk = pclk / (precaler value + 1)/ (divider value)
TCFG0 : 设置预分频系数
TCFG1 : 设置分频系数

TCFG0 :TCFG0
TCFG1:
在这里插入图片描述

定时器时钟框图:
定时器时钟体系

② 设置定时器初值(TCNTBn、TCMPBn)

设置初值buffer

③ 加载初始值(配置TCON)

定时器控制寄存器
定时器0控制寄存器

注意:在手动加载初值之后需要在下一次写入之前将改位清除

④ 设置为自动加载并启动

对TCON相应位进行配置就可以了,先清除再配置为相应的位


定时器初始化函数:timer0_init.c

void time0_init(void)
{
	//设置时钟
	TCFG0 = 99;	
	TCFG1 &= ~(15<<0);
	TCFG1 |= (3<<0);	
	
	//设置初始
	TCNTB0 = 31250;//Time0周期为1S

	//加载初值
	TCON &= ~(1<<1);
	TCON |= (1<<1);
	
	//清除手动加载位
	TCON &= ~(1<<1);

	//启动自动重加载、启动定时器
	TCON &= ~((1<<0)|(1<<3));
	TCON |= ((1<<0)|(1<<3));

	
}

⑤ 配置定时器中断

  1. 开启总中断
  2. 配置中断向量表以及响应函数
  3. 配置中断服务函数

这个部分可以参考外部中断进行配置

猜你喜欢

转载自blog.csdn.net/Utotao/article/details/88068642