1-5、ARM开发步步深入之玩转中断

实验目的:触发外部中断,控制LED灯的亮灭,借此掌握S3C2410中断处理操作。

实验环境及说明:恒颐S3C2410开发板H2410。选择开发板上的外部中断EINT0(复用引脚GPF0)引脚作为本次中断的触发源,通过触发这个中断来控制LED灯的亮灭。

实验思路:开发板上电启动后,自动将NandFlash开始的4K数据复制到SRAM中,然后跳转到0地址开始执行。然后设置系统及中断指针,初始化LED灯管脚和中断控制器,之后进入main函数死循环等待中断的发生,若EINT管脚电平发生变化则触发中断,调用中断处理函数点亮/熄灭LED灯。

知识掌握:ARM处理器各种工作模式和S3C2410中断控制器
一、ARM处理器各种工作模式:在这里只需要掌握系统模式和中断模式即可,详细的资料自己search一下。
★各种工作模式:用户模式(User,usr)正常程序执行的模式;系统模式(System,sys)用于运行特权级的操作系统任务;快速中断模式(FIQ,fiq)用于高速数据传输和通道处理;外部中断模式(IRQ,irq)用户通常的中断使用;特权模式(Supervisor,sve)供操作系统使用的一种保护模式;数据访问中止模式(Abort,abt)用于虚拟存储及存储保护;未定义指令中止模式(Undefin- ed,und)用于支持通过软件仿真硬件的协处理器。
★发生中断:ARM处理器对异常中断的响应过程是首先保存处理器当前状态、中断屏蔽位及CPSR寄存器中的各个条件标志位。这是通过将当前程序状态寄存器CPSR的内容保存到将要执行的异常中断对应的SPSR寄存器中实现的。其次设置当前程序状态寄存器CPSR中相应的位。再次将寄存器LR_mode(R14_mode)设置成返回地址。最后将PC设置成该异常中断的中断向量地址,从而跳转到对应的中断处理程序处执行。
中断返回:首先恢复被中断程序的处理器状态,也就是将SPSR_mode 内容复制到CPSR。然后返回到发生异常中断指令的下一条指令处执行,即将LR_mode(R14_mode)寄存器的内容复制到PC中。
★ARM各异常中断及对应含义:复位(Reset)当处理器复位引脚有效时,系统产生复位,程序跳转到复位异常中断处理程序处执行,复位异常中断的优先级是最高优先级的中断。通常复位产生有下面几种情况:系统加电时、系统复位时、各种不同的ARM处理器的复位有一些区别的,具体的参见后面的实例中的描述;未定义的指令(Undefined instruction)当ARM处理器或者系统中的协处理器认为当前指令未定义时,产生该中断,可以通过该异常中断仿真浮点向量运算;软件中断(Software Interrupt SWI)这是由用户定义的中断指令,可用于用户模式下的程序调用特权操作指令;数据访问中止(Data Abort)数据访问指令的目标地址不存在,或者该地址不允许当前指令访问,处理器产生数据访问中止异常中断;外部中断请求(IRQ)当处理器的外部中断请求引脚有效,或者CPSR寄存器的I控制位被清除时,处理器产生外部中断请求,应用中对于IRQ的中断处理是比较关键的技术;快速中断请求(FIQ)当处理器的外部中断请求引脚有效,或者CPSR寄存器的F控制位被清除时,处理器产生外部中断请求。

二、S3C2410中断控制器
CPU运行过程中得知外部发生不可预知事件的两种方法:查询方式---实现简单,但是占用资源过高;中断方式---实现相对复杂,但是效率高,是常用的方法。使用中断方式时又分为两大类:内部中断和外部中断。
★S3C2410提供了以下内部中断控制寄存器。
●SUBSRCPND寄存器:它用来表示INT_RXD0、INT_TXD0等中断是否发生(注:这些中断是某一大类中断中的子类),每位对应一个中断。当这些中断发生并且没有被INTSUBMSK寄存器屏蔽,则它们中的若干位将汇集出现在SRCPND寄存器的某一位上。要清除中断,往此寄存器中某位写1。
●INTSUBMSK寄存器:与SUBSRCPND寄存器对应,它用来屏蔽SUBSRCPND寄存器所标识的中断。INTSUBMSK寄存器中某位设置1时,对应的中断被屏蔽。
●SRCPND寄存器:它每一位被用来表示一个/一类中断是否发生。要清除某一位,往此位写1,具体参考数据手册。
●INTMSK寄存器:与SRCPND寄存器对应,用来屏蔽SRCPND寄存器所标识的中断。INTMSK寄存器中某位被设为1时,对应的中断被屏蔽,它只能屏蔽IRQ中断,不能屏蔽FIQ。
●INTMOD寄存器:它某位被设为1时,对应的中断被设为FIQ。同一时间,INTMOD只能有一位被设为1。
●PRIORITY寄存器:当有多个普通中断同时发生时,中断控制器选出最高优先级的中断,首先处理它。中断优先级通过7个仲裁器来完成,每个仲裁器基于一个位仲裁器模式控制(ARB_MODE,对应寄存器的[6:0]位)和选择控制信号(ARB_SEL,对应寄存器的[20:7]位)的两位来处理6个中断请求。
●INTPND寄存器:经过中断优先级选出优先级最高的中断后,这个中断在INTPND寄存器中的相应位被置1,随后CPU进入中断模式处理它,同一时间,此寄存器只有一位被置1。在ISR中,可以根据这个位确定是哪个中断,清除中断时,往此位写入1。
●INTOFFSET寄存器:用来表示INTPND寄存器中哪位被置1了,即INTPND寄存器中位[x]为1时,INTOFFSET寄存器的值为x(x为0-31)。清除SRCPND、INTPND寄存器时,INTOFFSET寄存器被自动清除。
★S3C2410提供了以下外部中断控制寄存器。
24个外部中断占用GPF0~GPF7(EINT0~EINT7)、GPG0~GPG15(EINT8~EINT23)。用这些脚做中断输入,则必须配置引脚为中断,并且不要上拉。
●EXTINT0~EXTINT2寄存器:设定EINT0~EINT23的触发方式。
●EINTFLT0~EINTFLT3寄存器:控制滤波时钟和滤波宽度。
●EINTPEND寄存器:这个是中断挂起寄存器,清除时要写1。当一个外部中断(EINT4~EINT23)发生后,那么相应的位会被置1。为什么没有EINT0~EINT3,看看SRCPND就知道了,里面没有EINT4~EINT23的位子,所以有了EINTPEND。
●EINTMASK寄存器:屏蔽中断用的,某位为1时,此次中断无效。


关键代码解析:
★head.S头文件来初始化,设置中断模式、系统模式的栈,设置好中断处理函数
.text
.global _start
_start:
@中断向量表处理函数,只给出复位和普通中断模式的处理函数,其它异常未使用
    b   Reset
......
@0x18: 中断模式的向量地址
    b   HandleIRQ
@0x1c: 快中断模式的向量地址
HandleFIQ:
    b   HandleFIQ

Reset:                                                @复位处理
    bl  disable_watch_dog               @关门喂狗
    bl init_led                                       @初始化LED
    bl init_irq                                        @初始化中断
    msr cpsr_c, #0xd2                       @进入中断模式
    ldr sp, =3072                                 @设置中断模式栈指针
    msr cpsr_c, #0x5f                        @设置I-bit=0,开IRQ中断
    msr cpsr_c, #0x5f                        @设置I-bit=0,开IRQ中断    
    ldr lr, =halt_loop                           @设置返回地址
    ldr pc, =main                                 @调用main函数
halt_loop:
    b   halt_loop

HandleIRQ:                                         @中断处理
    sub lr, lr, #4                                     @计算返回地址
    stmdb   sp!,    { r0-r12,lr }              @保存使用到的寄存器。注意,此时的sp是中断模式的sp,初始值是上面设置的3072
    
    ldr lr, =int_return                             @设置调用EINT_Handle函数后的返回地址
    ldr pc, =EINT_Handle                    @调用中断服务函数,在interrupt.c中
int_return:
    ldmia   sp!,    { r0-r12,pc }^            @中断返回, ^表示将spsr的值复制到cpsr

★init.c文件实现GPIO及中断的初始化,主要代码:
/*
* LED1-2对应GPF4、GPF5
*/
#define GPF4_out        (1<<(4*2))      // LED1
#define GPF5_out        (1<<(5*2))      // LED2

void init_led(void)
{
    GPFCON |= GPF4_out|GPF5_out;
    GPFDAT |= (0x01<<4);   // 初始状态,LED4熄灭,LED5点亮
  GPFDAT &= (~(0x1<<5));
}

/*
* EINT0复用GPF0
*/
#define GPF0_eint      (2<<(2*0))     // EINT0

/*
* 初始化GPIO引脚为外部中断
* GPIO引脚用作外部中断时,默认为低电平触发、IRQ方式(不用设置INTMOD)
*/
void init_irq(void)
{
    GPFCON  |= GPF0_eint;
    // EINT0使能
    INTMSK   &= ~(1<<0);
    /*
     * 设定优先级:
     * ARB_SEL0 = 00b, ARB_MODE0 = 0,仲裁器1、6无需设置
     */
   PRIORITY &= ~((0x01);
}

★interrupt.c文件实现中断的处理,主要代码:
void EINT_Handle()
{
        unsigned long oft = INTOFFSET;
    
        // EINT0被按下
    GPFDAT |= (0x03<<4);   // 所有LED熄灭
    GPFDAT &= ~(1<<4);      // LED4点亮,LED5熄灭
    GPFDAT |= (1<<5);

        //清中断
    SRCPND &= ~(1<<oft);
    INTPND = 1<<oft;
}

posted @ 2010-06-14 16:54  stardream  阅读(1904)  评论(0编辑  收藏  举报