S3C2416裸机开发系列七_异常处理

发布者:Blissful5最新更新时间:2016-12-12 来源: eefocus关键字:S3C2416  裸机开发  异常处理 手机看文章 扫描二维码
随时随地手机看文章

arm7/arm9架构cpu有七种工作模式,分别为用户模式、快中断模式、中断模式、管理模式、中止模式、未定义模式和系统模式。除了用户模式与系统模式外,其它五种模式称为异常模式。当特定的异常出现时,cpu进入相应的模式。对于嵌入式设计来说,中断处理是必不可少的功能,因此笔者就arm的异常处理作一个简单的介绍。

1. 向量表

1.1. arm异常向量表

一些内存存储空间用来存储各个异常处理程序入口地址或存放异常处理程序首地址,这个存储区称为异常向量表。对于arm7/arm9,这个异常向量表的入口地址是0x0地址偏移处(高端向量为0xffff0000),相应的异常发生时,会从异常向量表偏移地址处取出异常处理程序的入口,进入并执行。

图1-1 arm异常向量表

1.2. 中断向量表

中断对于arm架构cpu来说,也只是一种异常模式。cpu外设中断都是通过请求IRQ(FIQ)线进入IRQ(FIQ)异常模式,完成外设中断的处理请求。但cpu很多外设都是需要使用中断请求的,而IRQ(FIQ)入口地址只有一个,因此中断请求进入IRQ(FIQ)异常模式后,是需要进一步判别哪一个外设正在请求中断,并进入相应外设的中断处理程序中。通常我们通过一个中断向量表来记录各个cpu外设中断处理程序的入口地址。这张表由我们自己维护,可随时更改相应的中断处理程序。

1.3. 中断嵌套

当中断发生后,内核会把返回地址保存到LR中,将CPSR复制到SPSR中,并转换为IRQ(FIQ)模式,从IRQ(FIQ)异常向量处取指。arm7/arm9在硬件上是不支持中断嵌套的,进入中断异常时,内核会自动置位IRQ、FIQ中断位,禁止中断嵌套。对于一些不重要或处理时间长的中断,不能中断嵌套,往往会丢失掉其它更重要的中断。可在中断处理中用软件的方式允许中断的嵌套,其步骤如下:

1.3.1. 进入IRQ时保存各个使用的寄存器和SPSR_irq;

1.3.2. 切换到系统模式并保存系统模式下链接寄存器LR_sys;

1.3.3. 调用C中断处理函数,可再次允许IRQ中断进行嵌套

1.3.4. 当C中断处理函数返回后,恢复IRQ模式,使用IRQ栈

1.3.5. 从IRQ栈中恢复工作寄存器和SPSR_irq;

1.3.6. 从IRQ中断处理程序中返回。

IRQ中断模式下重新再打开IRQ中断,再次发生中断时会把原IRQ的返回地址寄存器LR直接覆盖,因此进入IRQ后需切换到其它的模式再允许中断进行嵌套。在IRQ的各个外设中断处理函数中加入IRQ使能函数即可允许这个外设中断可被嵌套,不加,则IRQ位仍然禁止,不进行中断嵌套。

2. 异常处理代码实现

我们在启动代码s3c2416.s中修改各个异常向量进入的处理函数地址,其内容如下:

            AREA   RESET, CODE, READONLY

;        ENTRY

            ARM

Vectors     B      Reset_Handler       

            LDR     PC, Undef_Addr

            LDR     PC, SWI_Addr

            LDR     PC, PAbt_Addr

            LDR     PC, DAbt_Addr

         LDR     PC, Notuse_Addr

         B        IRQ_SaveContext

         LDR     PC, FIQ_Addr

 

        IMPORT  Undef_Handler

        IMPORT  SWI_Handler

        IMPORT  PAbt_Handler

        IMPORT  DAbt_Handler

        IMPORT  IRQ_Handler

        IMPORT  FIQ_Handler            

Reset_Addr  DCD  Reset_Handler

Undef_Addr  DCD  Undef_Handler

SWI_Addr    DCD  SWI_Handler

PAbt_Addr   DCD  PAbt_Handler

DAbt_Addr   DCD  DAbt_Handler

Notuse_AddrDCD   0           ; Reserved Address

FIQ_Addr    DCD  FIQ_Handler

IRQ_SaveContext

; 保存中断上下文,支持中断嵌套             

        SUB LR, LR, #4 ; 计算返回地址

        STMFD SP!, {R0-R12, LR} ;所有寄存器压栈保存

        MRS     R0, SPSR ; 保存中断前的CPSR(即现在的SPSR)

        STMFD   SP!, {R0}

        MSR CPSR_cxsf, #Mode_SYS|I_Bit ; 切换到系统模式 

        STMFD     SP!, {LR} ; 压栈系统模式LR   

                       

        LDR     R0, =IRQ_Handler ;系统模式下进行IRQ代码处理

        BLX R0 ; 调用中断处理函数

           

        LDMFD    SP!, {LR} ; 出栈系统模式LR

        MSR CPSR_cxsf, #Mode_IRQ|I_Bit ; 切换到IRQ模式                 

        LDMFD   SP!, {R0} ; 返回中断前的CPSR               

        MSR     SPSR_cxsf,R0

        LDMFD  SP!, {R0-R12, PC}^ ; ^表同时从spsr恢复给cpsr       

各个异常处理及外设IRQ中断我们在Exception.c模式中统一处理实现,其内容如下:

#include"s3c2416.h"

#include"Exception.h"

 

// 定义32个函数指针保存各IRQ中断入口函数

static void(*IRQ_Table[32])(void);

 

void Undef_Handler(void)

{

    while(1) {

 

    }

}

 

voidSWI_Handler(void)

{

    while(1) {

 

    }

}

 

voidPAbt_Handler(void)

{

    while(1) {

 

    }

}

 

voidDAbt_Handler(void)

{

    while(1) {

   

    }

}

 

voidFIQ_Handler(void)

{

    while(1) {

       

    }

}

 

voidIRQ_Register(unsigned char Channel, void (*Func)(void))

{

    if (Channel < 32) { // 32个外设中断

        IRQ_Table[Channel] = Func; // 注册相应中断处理函数

    }

}

 

voidIRQ_Handler(void)

{

    unsigned int Offset;

    if (rINTPND1 != 0) {

        // 第一组引起的中断处理        

        Offset = rINTOFFSET1;

        rSRCPND1 |= (0x01<

        rINTPND1 |= (0x01<

        if (IRQ_Table[Offset]) { // 中断处理需己注册

            (IRQ_Table[Offset])(); // 调用相应的中断处理

        }

    } else if (rINTPND2 != 0) {

        // 第二组引起的中断处理    

        Offset = rINTOFFSET2;

        rSRCPND2 |= (0x01<

        rINTPND2 |= (0x01<

        switch (Offset) {

            case 0:

            // INT_2D 中断处理 

                break;

            case 4:

            // INT_PCM0 中断处理   

                break;

            case 6:

            // INT_I2S0 中断处理   

                break;

            default:

                break;

        }

    }

}

在使用相应的外设中断时,我们需要在外设初始化时先注册相应的中断处理函数,再打开中断,定时器4作为系统时钟简单计数的例程如下:

unsigned int SystemTick = 0;

voidTimer4_IRQ(void)

{  

    SystemTick++;

    rSRCPND1 |= (0x01<

    rINTPND1 |= (0x01<

}

 

voidTimer4_Init()

{

// 定时器4时钟频率为PCLK(50M)/(0+1)/16=3.125MHZ

    rTCFG1 &= ~(0xf << 16);

    rTCFG1 |= (0x3 << 16);  // Timer4 16分频

    rTCFG0 &= ~(0xff << 8);

    rTCFG0 |= (0 << 8);

    rTCNTB4 = 3125; // System Tick设1ms

    rTCON |= (0x1 << 21); // 更新计数值

    rTCON &= ~(0x1 << 21); // 清除

    rTCON |= (0x1 << 22); // 自动重装载

   

    IRQ_Register(INT_TIMER4,Timer4_IRQ);

    rINTMOD1 &= ~(1 << 14); // Timer4IRQ 模式

    rINTMSK1 &=~(1 << 14); // Timer4开中断

}

3. 附录

Exception.h/Exception.c,异常处理及IRQ跳转处理模块实现。

s3c2416.s,引入外部异常处理及IRQ中断嵌套处理修改后的启动文件

http://pan.baidu.com/s/1pJ7AErp


关键字:S3C2416  裸机开发  异常处理 引用地址:S3C2416裸机开发系列七_异常处理

上一篇:S3C2416裸机开发系列八_MDK启动代码工程应用实例
下一篇:S3C2416裸机开发系列五_Nand驱动以及Nand启动

推荐阅读最新更新时间:2024-03-16 15:24

S3C2416裸机开发系列十五_GCC下uCOS的移植(2)
4. uCOS配置 uCOS是可裁减实时操作系统,可以根据实际的应用对内核未使用到的功能进行裁减,以进一步节省系统宝贵的硬件资源,通常可用的uCOS-II内核代码在6K~26K,这在uCOS-II配置文件os_cfg.h中进行配置,这个配置文件在源码目录为os_cfg_r.h,从目录中拷贝添加到uCOS/uCOS-II/Cfg目录中,并重命名为os_cfg.h。 #ifndef OS_CFG_H #define OS_CFG_H /* ---------------------------- MISCELLANEOUS -------------------------- */ #define OS_CFG_APP_HOOKS_E
[单片机]
<font color='red'>S3C2416</font><font color='red'>裸机</font><font color='red'>开发</font>系列十五_GCC下uCOS的移植(2)
函数指针数组在ARM异常中断处理中的应用
介绍一种简洁、高效、灵活的ARM异常中断处理方法。 在ARM中,由于所有的中断都使用同一个异常中断入口地址,即0x00000018。因此需要在异常中断处理程序中根据相应的中断号调用对应的中断服务函数。 一般有两种处理方式: 1. 在汇编中保存现场,然后调用C语言编写的中断处理程序,任务处理完成之后,再返回到汇编中恢复现场,并返回到断点。其中C语言编写的中断处理程序,通过switch语句对INTOFFSET进行判断,然后散转执行对应的服务函数。 IMPORT IRQ_EXCEPTION 0x00000018 LDR PC,=IRQ_E
[单片机]
jz2440裸机开发与分析: 点亮LED灯之C语言3
对于之前提出了栈这一概念下面我们要提出问题: 1.为何要使用栈 答:c函数要用 2.如何使用栈 答:a.保存局部变量 b.保存lr等寄存器 3.调用者如何传参数给被调用者 start.s .text .global _start _start: /* 设置内存: sp 栈 */ ldr sp, =4096 /* nand启动 */ // ldr sp, =0x40000000+4096 /* nor启动 */ mov r0, #4 bl led_on ldr r0, =100000 bl delay mov r0, #5 bl led_on halt: b halt c代码 void
[单片机]
一起学mini2440裸机开发(十)--mini2440外部中断实验
我今天一整天都在试着将TQ2440的那种处理中断的方法(即安装中断向量表)移植到MDK中的mini2440,但是一直没成功,这种方法一直没成功,后来又想,还是先从最简单的开始吧,就是不利用中断向量表,直接像利用51单片机那样的中断一样使用它,但是也没成功。考虑到程序跑飞的可能性,将程序利用MDK中的Download功能下载到了Nor Flash中去,竟然行了,想了想原因,明白是怎么回事了。我原来是利用jlink调试的方法,这种调试方式是直接将程序放到了SDRAM的0x3000 0000处,如果发生中断后,比如发生了普通中断IRQ,那么PC指针被强制设为0x0000 0018,而我的程序是放在了0x3000 0000处,在地址0x00
[单片机]
一起学mini2440<font color='red'>裸机</font><font color='red'>开发</font>(十)--mini2440外部中断实验
arm处理异常处理swi
ARM处理器共有7中运行模式: 用户模式(usr) -- 正常程序执行模式 |-- |-- 快速中断模式(fiq) -- 用于高速数据传输和通道处理 特 | 异 | 外部中断模式(irq) -- 用于通常的中断处理 权 --| 常 --| 管理员模式(svc) -- 供操作系统使用的一种保护模式 模 | 模 | 数据访问中止模式(abt) -- 用于虚拟存储及存储保护 式 | 式 |-- 未定义指令中止模式(
[单片机]
如何处理ARM的异常和中断
异常和中断处理,负责处理错误,中断和其他由外部系统触发的事件。 ARM有7种异常,数据中止、快速中断请求、中断请求、预取址中止、软件中断、复位及未定义指令。 2种类型的中断,第一类是由外设引起的,即IRQ和FIQ。第二类是一条引发中断的特殊指令SWI。两种中断都会挂起正常的程序执行。 异常是需要中止指令正常执行的任何情形,包括ARM内核产生复位,取指或存储器访问失败,遇到未定义指令,执行了软件中断指令,或者出现了个外部中断等。异常处理就是处理这些异常情况的方法。大多数异常都对应一个软件的异常处理程序,一个在异常发生时执行的软件程序。 每种异常都导致内核进入一种特定的模式。每个处理器模式都
[单片机]
ARM 处理器如何处理异常
当异常发生时,ARM处理器尽可能完成当前指令(除了复位异常)后,再去处理异常。并执行如下动作: 1. 进入与特定的异常相应的操作模式。 2. 将引起异常指令的下一条指令的地址保存到新模式的r14中。 3. 将CPSR的原值保存到新模式的SPSR中。 4. 通过设置CPSR的第7位来禁止IRQ。如果异常为快速中断。则还要设置CPSR的第6位来禁止快速中断。 5. 给PC强制赋向量地址值。
[单片机]
三星6410裸机程序开发5:使用三星官方6410_Test工程开发裸机程序
在 三星6410裸机程序开发1 文章中,说到的是采用eclipse + windows安装版的专为ARM嵌入式处理器预编译的GNU工具组合来开发6410的裸机程序。由于遇到了中断问题,所以不得不切换开发环境。 幸运地是,不仅顺利切换到RVDS环境,而且还发现了三星官方6410_Test工程。这个工程提供了芯片大部分功能模块的裸机程序实现和测试用例程序。 1. RVDS环境安装 RVDS(RealView® Development Suite)是ARM公司继SDT与ADS1.2之后主推的新一代开发工具,向下兼容以前的版本(ADS v1.2.1、1.1、1.0.1)。由于6410_Test工程采用的是RVDS2.2,所以当然是
[单片机]
三星6410<font color='red'>裸机</font>程序<font color='red'>开发</font>5:使用三星官方6410_Test工程<font color='red'>开发</font><font color='red'>裸机</font>程序
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved