s3c2440异常与中断

mac2025-05-03  5

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接: https://blog.csdn.net/Utotao/article/details/88068642

1.s3c2440模式与状态

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

1.1.模式

ARM一共有7种模式

1. usr模式 1

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


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个字节 12

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

1.3寄存器

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

CPSR寄存器:


T位:state bits(ARM state、Thumb state) 1
F位:FIQ disable,为1时所用的FIQ禁止 1
I位:IRQ disable,为1时,禁止所有IRQ 1
1.3.2.其余寄存器

关于r0-r12的说明:

关于r13-r15的说明:

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

2.异常处理流程

2.1.进入异常操作

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

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

2.2.退出异常操作

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

3.undefined异常处理实例

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

①. 配置异常向量表

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

②. 配置响应函数

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

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

② 保存r0-r12,lr

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

step3:中断服务函数

bl interrupt_service_function 1

step4:恢复现场

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

③. 配置异常服务函数

使用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

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

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

/* INTMSK 用来屏蔽中断, 1-masked

bit0-eint0bit2-eint2bit5-eint8_23 */

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

bit0-eint0bit2-eint2bit5-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 : TCFG1:

定时器时钟框图:

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

③ 加载初始值(配置TCON)

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

④ 设置为自动加载并启动

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


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

void time0_init(void) { //设置时钟 TCFG0 = 99; TCFG1 &= ~(15<<0); TCFG1 |= (3<<0); //设置初始 TCNTB0 = 31250;//Time0周期为1S //加载初值 TCON &amp;= ~(1&lt;&lt;1); TCON |= (1&lt;&lt;1); //清除手动加载位 TCON &amp;= ~(1&lt;&lt;1); //启动自动重加载、启动定时器 TCON &amp;= ~((1&lt;&lt;0)|(1&lt;&lt;3)); TCON |= ((1&lt;&lt;0)|(1&lt;&lt;3));

}

⑤ 配置定时器中断

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

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

</div> <link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-e9f16cbbc2.css" rel="stylesheet"> </div>
最新回复(0)