ARM9__中断

ARM体系的CPU有7种工作模式

用户模式   usr ARM处理器正常的程序执行状态

快速中断模式 fiq 用于高速数据传输或通道处理

中断模式 irq 用于通用中断处理

管理模式 svc 操作系统使用的保护模式

数据访问终止模式 abt 虚拟存储及存储保护

系统模式 sys 运行具有特权的操作系统任务

未定义指令终止模式 und 支持硬件协处理器的软件仿真


CPSR寄存器 当前程序状态寄存器

标致当前寄存器的工作状态和所处的工作模式

中断怎么用:

1 中断发生

初始化,中断使能

保存别人的状态

2 中断处理

分辨中断源

进行处理

清理中断

3

恢复别人状态,程序继续运行


注意: ①使能、禁止

   ②怎么分辨状态寄存器

③高低电平,上升下降沿触发

④引脚相关硬件设置

⑤优先级寄存器


中断中的寄存器

1 SUBSRCPND寄存器

用来标识INT_RXD0、INT_TXD0等中断是否已经发生

2 INTSUBMSK寄存器

用来屏蔽SUBSRCPND寄存器所标识的中断,如果设为1,则该中断被屏蔽

3 SRCPND寄存器

用来标识哪一类中断是否已经发生

4 INTMSK寄存器

用来屏蔽SRCPND寄存器所标识的中断

5 INTMOD寄存器

某位被设置为1,则该中断对应为FIQ

6 PRIORITY寄存器

用来设置优先级

ARB_MODE 选择仲裁器的工作模式

ARB_SEL 控制输入信号的优先级

7 INTPND寄存器

优先级确定后,这个中断在INTPND寄存器中相应的位被置为1,随后CPU进入中断模式进行处理

8 INTOFFSET寄存器

用来标识INTPND寄存器中哪位被置为1了,在清除SRCPND,INTPND寄存器时,INTOFFSET寄存器被自动清除。



实例

head.S

.text 
.global _start 
_start:
@******************************************************************************       
@ 中断向量,本程序中,除Reset和HandleIRQ外,其它异常都没有使用
@******************************************************************************       
    b   Reset


@ 0x04: 未定义指令中止模式的向量地址
HandleUndef:
    b   HandleUndef  
 
@ 0x08: 管理模式的向量地址,通过SWI指令进入此模式
HandleSWI:
    b   HandleSWI


@ 0x0c: 指令预取终止导致的异常的向量地址
HandlePrefetchAbort:
    b   HandlePrefetchAbort


@ 0x10: 数据访问终止导致的异常的向量地址
HandleDataAbort:
    b   HandleDataAbort


@ 0x14: 保留
HandleNotUsed:
    b   HandleNotUsed


@ 0x18: 中断模式的向量地址
    b   HandleIRQ


@ 0x1c: 快中断模式的向量地址
HandleFIQ:
    b   HandleFIQ


Reset:                  
    ldr sp, =4096           @ 设置栈指针,以下都是C函数,调用前需要设好栈
    bl  disable_watch_dog   @ 关闭WATCHDOG,否则CPU会不断重启
    
    msr cpsr_c, #0xd2       @ 进入中断模式 0xd2~110     10010 最后5位IRQ模式
    ldr sp, =3072           @ 设置中断模式栈指针


    msr cpsr_c, #0xd3       @ 进入管理模式 0xd3 10011 最后5位SVC模式
    ldr sp, =4096           @ 设置管理模式栈指针,
                            @ 其实复位之后,CPU就处于管理模式,
                            @ 前面的“ldr sp, =4096”完成同样的功能,此句可省略


    bl  init_led            @ 初始化LED的GPIO管脚 bl 跳转的意思
    bl  init_irq            @ 调用中断初始化函数,在init.c中
    msr cpsr_c, #0x53       @ 设置I-bit=0,开IRQ中断 0x53~01010011 开中断
    
    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             @ 设置调用ISR即EINT_Handle函数后的返回地址  
    ldr pc, =EINT_Handle            @ 调用中断服务函数,在interrupt.c中
int_return:
    ldmia   sp!,    { r0-r12,pc }^  @ 中断返回, ^表示将spsr的值复制到cpsr


init.c

/*
 * init.c: 进行一些初始化
 */ 


#include "s3c24xx.h" //引用该头文件,里面含有许多地址


/*
 * LED1,LED2,LED4对应GPF4、GPF5、GPF6
 */

//将IO口设置为输出模式
#define GPF4_out (1<<(4*2))
#define GPF5_out (1<<(5*2))
#define GPF6_out (1<<(6*2))

//将IO口设置全部置为1
#define GPF4_msk (3<<(4*2))
#define GPF5_msk (3<<(5*2))
#define GPF6_msk (3<<(6*2))


/*
 * S2,S3,S4对应GPF0、GPF2、GPG3
 */

//将IO口设置为中断模式
#define GPF0_eint     (0x2<<(0*2))
#define GPF2_eint     (0x2<<(2*2))
#define GPG3_eint     (0x2<<(3*2))

//将IO口全部置为高
#define GPF0_msk    (3<<(0*2))
#define GPF2_msk    (3<<(2*2))
#define GPG3_msk    (3<<(3*2))


/*
 * 关闭WATCHDOG,否则CPU会不断重启
 */
void disable_watch_dog(void)
{
    WTCON = 0;  // 关闭WATCHDOG很简单,往这个寄存器写0即可
}


void init_led(void)
{
    // LED1,LED2,LED4对应的3根引脚设为输出
    GPFCON &= ~(GPF4_msk | GPF5_msk | GPF6_msk);
    GPFCON |= GPF4_out | GPF5_out | GPF6_out;
}


/*
 * 初始化GPIO引脚为外部中断
 * GPIO引脚用作外部中断时,默认为低电平触发、IRQ方式(不用设置INTMOD)
 */ 
void init_irq( )
{
    // S2,S3对应的2根引脚设为中断引脚 EINT0,ENT2
    GPFCON &= ~(GPF0_msk | GPF2_msk);
    GPFCON |= GPF0_eint | GPF2_eint;


    // S4对应的引脚设为中断引脚EINT11
    GPGCON &= ~GPG3_msk;
    GPGCON |= GPG3_eint;
    
    /*

外部中断屏蔽寄存器EINTMASK

EINT4---EINT23使能需要在EINTMASK中使能

所以对这个寄存器写0

  */
    EINTMASK &= ~(1<<11);
       
    /*
     * 设定优先级:
     * ARB_SEL0 = 00b, ARB_MODE0 = 0: REQ1 > REQ3,即EINT0 > EINT2
     * 仲裁器1、6无需设置
     * 最终:
     * EINT0 > EINT2 > EINT11即K2 > K3 > K4
     */
    PRIORITY = (PRIORITY & ((~0x01) | (0x3<<7))) | (0x0 << 7) ;


    // EINT0、EINT2、EINT8_23使能
    INTMSK   &= (~(1<<0)) & (~(1<<2)) & (~(1<<5));
}


interrupt.c


#include "s3c24xx.h"


void EINT_Handle()
{

    //INTOFFSET用来标识哪一位被置为1,从而判断哪个按键按下
    unsigned long oft = INTOFFSET;

    unsigned long val;
    
    switch( oft )
    {
        // S2被按下
        case 0: 
        {   
            GPFDAT |= (0x7<<4);   // 所有LED熄灭
            GPFDAT &= ~(1<<4);      // LED1点亮
            break;
        }
        
        // S3被按下
        case 2:
        {   
            GPFDAT |= (0x7<<4);   // 所有LED熄灭
            GPFDAT &= ~(1<<5);      // LED2点亮
            break;
        }


        // K4被按下
        case 5:
        {   
            GPFDAT |= (0x7<<4);   // 所有LED熄灭
            GPFDAT &= ~(1<<6);      // LED4点亮                
            break;
        }


        default:
            break;
    }


    //清中断
    if( oft == 5 ) 
        EINTPEND = (1<<11);   // EINT8_23合用IRQ5

//EINTPEND 外部中断屏蔽寄存器 1表示清除
    SRCPND = 1<<oft; //中断是否发生,写1清零
    INTPND = 1<<oft; //优先级选中后,会被置1  清除中断,这里写1
}

你可能感兴趣的:(中断,ARM9)