六、mini2440裸机程序之中断控制器(2)外部按键中断

1.管脚介绍

 六、mini2440裸机程序之中断控制器(2)外部按键中断_第1张图片


2.相关知识点介绍

    1)中断源相关仲裁器 :

 

    2)异常向量表:

 六、mini2440裸机程序之中断控制器(2)外部按键中断_第2张图片

 

   3)PSR格式(通过对I、F位置'0',可以开启IRQ和FIQ )

        arm920t包含了一个CPSR(当前程序状态寄存器) , 5个SPSRs(保存程序状态寄存器  :  用于异常中断处理程序保存CPSR的值)  , 

其中的I  , f  位分别是用来使能和禁止IRQ和FIQ的(置'0'使能 ) ,  M[4:0]是用来选择处理器运行模式的

六、mini2440裸机程序之中断控制器(2)外部按键中断_第3张图片

注:

在配置好相关中断控制寄存器之后要通过置'0'  PSR中的I位或者F位来使能IRQ或者FIQ  ,  如果中断服务子程序是用c语言写的话还要在

启动中断使能之前通过设置M[4:0]来进入IRQ模式下的sp.



    4) 进入一个异常时CPU做的事

            ①把下一条指令的的地址放入相应的LR寄存器里  .  如果是从AMR状态下进入异常的,那就是PC的下一条(PC+4 or PC+8,

主要依据于异常模式,具体可以参考下表)指令被拷贝到LR  ;  如果是从THUMB模式下进入异常的,那当前PC偏移值会被写入LR.


            ②拷贝CPSR到相应模式下的SPSR

            ③迫使的CPSR模式位的值变为相应异常模式的值

            ④迫使PC从相关异常向量中获取下一条要执行的指令

通常也设置中断禁止标志来阻止另外的难于管理的嵌套中断

    5)退出一个异常时CPU所做的活动

            ①取出lr里的值,减去适当的偏移量,赋给PC

            ②把SPSR的内容拷贝到CPSR

            ③如果在进入异常处理时有设置中断禁止标志,则清除中断禁止标志

           

 

3.相关寄存器介绍:

 

    ①SRCPND

六、mini2440裸机程序之中断控制器(2)外部按键中断_第4张图片

注:

这个寄存器是用于指明哪个中断源产生中断信号了,1为相应中断源产生中断请求,具体能不能被服务还得看其它寄存器的设置.

在进入中断服务子程序后要对其写'1'清零.


    ②INTMOD


注:

采用默认模式IRQ就好了

 

    ③INTMSK

六、mini2440裸机程序之中断控制器(2)外部按键中断_第5张图片

注:

默认所有中断都被屏蔽的  ,  我们不能开启这个中断屏蔽位 .

配置如下:

INTMSK &=~( 1 << 5 )

 

    ④PRIORITY


注:

关于优先级设置 ,ARB_SEL6设置为00 , 这样仲裁器6的REQ1就拥有了第二高的优先级了. 同理,ARB_SEL1也设置为00 ,

然后不使能优先级自动轮流翻转.

配置如下:

PRIOITY &=  ~( ( 0x3<< 19 ) | ( 0x3 << 9 ) | ( 1 << 1) | ( 1 << 6 ) )

 

    ⑤INTPND


注:

这个寄存器是用于指明哪一个中断请求可以被响应.

在进入中断服务子程序后对其写'1'清零.

 

     ⑥INTOFFSET


注:

通过读取这个寄存器的值可以得知中断源.

 

    ⑦EXTINT1/2

 

六、mini2440裸机程序之中断控制器(2)外部按键中断_第6张图片

注:

FLTENn用于使能或者禁止滤波 :   采用滤波使能   '1'

EINTn用于设置设置信号触发模式 :  选择下降沿触发'01x'

EXTINT1 |= (0x05<<1) | (0x05<<13) | (0x05 << 21) |(0x05 << 25) | (0x05 << 29)

EXTINT2 |= (0x05 << 13)

 

       ⑧EINTMASK


这个寄存器用于屏蔽外部中断源  ,  置'1'为屏蔽相应中断.

配置结果如下:

EINTMASK &=~( 0x3F << 8 );

 

    ⑨EINTPEND

六、mini2440裸机程序之中断控制器(2)外部按键中断_第7张图片

注:

这个寄存器是用于指明哪一个外部中断源产生中断请求.

在进入中断服务子程序后对其写'1'清零.

 

4.程序设计流程图

     1)主流程图:

 六、mini2440裸机程序之中断控制器(2)外部按键中断_第8张图片

     2)中断服务子程序流程图

 六、mini2440裸机程序之中断控制器(2)外部按键中断_第9张图片   

     3)中断服务处理子函数


5.程序设计

    1)Makefile

interrupt.bin : head.o interrupt_main.o
    arm-linux-ld -Tinterrupt.lds -o interrupt_elf $^
    arm-linux-objcopy -O binary -S interrupt_elf $@
    arm-linux-objdump -D -m arm interrupt_elf > interrupt.dis

%.o : %.S
    arm-linux-gcc -Wall -c -o $@ $<

%.o : %.c
    arm-linux-gcc -Wall -c -o $@ $<

clean :
    rm -f interrupt_elf interrupt.dis interrupt.bin *.o *.bak

    2)interrupt.lds

SECTIONS {
    first    0x00000000 : {head.o interrupt_main.o}

}


    3)head.S

@与中断相关
.equ    INTMSK    ,    0x4A000008
.equ    PRIOITY    ,    0x4A00000C
.equ    EINTMASK,    0x560000A4
.equ    EXTINT1    ,    0x5600008C
.equ    EXTINT2    ,    0x56000090

@与看门狗相关
.equ    WTCON    ,    0x53000000
@与管脚配置相关
.equ    GPGCON    ,    0x56000060
.equ    GPGUP    ,    0x56000068
@与灯光配置相关的
.equ    GPBCON    ,    0x56000010
.equ    GPBDAT    ,    0x56000014

.Text
.global _start
_start:
/***********设置中断向量表*************/
    b    ResetInit    @复位异常入口
HandlerUndef:
    b    HandlerUndef    @未定义异常入口
HandlerSWI:
    b    HandlerSWI    @软中断异常入口
HandlerPabort:
    b    HandlerPabort    @取指中止异常入口
HandlerDabort:
    b    HandlerDabort    @数据中止异常入口
HandlerNotUsed:
    b    HandlerNotUsed        @保留

    b    HandlerIRQ    @中断异常入口
HandlerFIQ:
    b    HandlerFIQ    @快中断异常入口
/************END设置中断向量表***********/

ResetInit:
/**************关闭看门狗****************/
    ldr    r0 , =WTCON
    mov    r1 , #0x0
    str    r1 , [r0]
/************END关闭看门狗***************/


/***********设置系统模式下的sp***********/
    @复位默认进入系统模式
    ldr    sp , =4096
/********END设置系统模式下的sp***********/


/********配置相关管脚为外部中断功能******/
    ldr    r0 , =GPGCON
    ldr    r1 , [r0]
    ldr    r2 , =(3<<22)|(0x3f<<10)|(0x03<<6)|(0x03)
    bic    r1 , r1 , r2
    ldr    r2 , =(2<<22)|(42<<10)|(2<<6)|(2<<0)
    orr    r1 , r1 , r2
    str    r1 , [r0]
    
    ldr    r0 , =GPGUP
    mov    r1 , #0
    str    r1 , [r0]
    
/*******END配置相关管脚为外部中断功能****/

/************初始化LED灯管脚*************/
    @把LED1-4管脚置为输出
    ldr    r0 , =GPBCON
    ldr    r1 , [r0]        @把GPBCON里的内容加载到r1里
    ldr    r2 , =(0xFF<<10)
    bic    r1 , r1 ,r2    @操作数取反码或上r1,用于清零工作
    ldr    r2 , =(0x55<<10)
    orr    r1 , r1 , r2
    str    r1 , [r0]    
    
    @灯全灭
    ldr    r0 , =GPBDAT
    ldr    r1 , [r0]    
    ldr    r2 , =(0x0F<<5)
    orr    r1 , r1 , r2
    str    r1 , [r0]
/***********END初始化LED灯管脚************/



/********调用配置中断控制器子程序********/
    bl    IntConfigure    
/*******END调用配置中断控制器子程序******/


/*进入中断模式设置中断模式下的sp退出到系统模式
*使能IRQ中断*/


    @进入中断模式,禁止中断,其中cpsr后的_c表示cpsr[7:0]
    msr    cpsr_c , 0xd2

    @设置sp
    ldr    sp , =3072
    
    @退出到系统模式,使能IRQ中断
    msr    cpsr_c , 0x5f
    
    
/*END进入中断模式设置中断模式下的sp退出到系统模式*/


/************死循环等待中断**************/
halt_loop:
    b    halt_loop
/************END死循环等待中断***********/



/*************IRQ中断服务子程序**********/

HandlerIRQ:
    

    @因为在产生中断异常时,lr存的是当前指令的下一条指令,所以要减四
    sub    lr , lr , #4
    
    @把相关寄存器压入中断模式下的栈
    @db表示sp每次传送内容前减1
    stmdb    sp! , {r0-r12 , lr}
    
    @禁止IRQ中断,其中cpsr后的_c表示cpsr[7:0]
    mrs    r1 , cpsr_all
    orr    r1 , r1 , #(1<<7)
    msr    cpsr_all , r1
    
    @调用中断服务处理函数
    ldr    lr , =IRQ_Return
    ldr    pc , =main
    
IRQ_Return:

    @把栈里面的内容推出到相应寄存器里,并把lr推到pc寄存器实现跳转
    @ia表示每次传送后加1 , 当寄存器列表中包含了pc寄存器,选用^为后缀,就会把spsr拷贝到cpsr
    ldmia    sp! , {r0-r12 , pc}^
        
/********END IRQ中断服务子程序***********/    





/***********配置中断控制器子程序*********/
IntConfigure:
    @关闭EINT8_23的中断屏蔽位
    ldr    r0 , =INTMSK
    bic    r1 , r1 , #(1<<5)
    str    r1 , [r0]

    @ARB_SEL6 = 00 , ARB_SEL1 = 00
    ldr    r0 , =PRIOITY
    ldr    r2 , =(0x03<<19)|(0x03<<9)|(0x01<<6)|(0x01<<1)
    bic    r1 , r1 , r2
    str    r1 , [r0]

    @关闭EINT19,EINT15,EINT14,EINT13,EINT11,EINT8屏蔽
    ldr    r0 , =EINTMASK
    ldr    r2 , =(0x3F<<8)
    bic    r1 , r1 , r2
    str    r1 , [r0]

    @使能管脚滤波,下降沿触发
    ldr    r0 , =EXTINT1
    ldr    r1 , =(0x05<<1)|(0x05<<13)|(0x05<<21)|(0x05<<25)|(0x05<<29)
    str    r1 , [r0]
    
    ldr    r0 , =EXTINT2
    ldr    r1 , =(0x05<<13)
    str    r1 , [r0]
    
    bx    lr
/****************END IntConfigure***********/


    4)interrupt_main.c

#define    GPBDAT        (*(volatile unsigned long *)0x56000014)

#define    INTOFFSET    (*(volatile unsigned long *)0x4A000014)
#define EINTPEND    (*(volatile unsigned long *)0x560000A8)
#define SRCPND        (*(volatile unsigned long *)0x4A000000)
#define INTPND        (*(volatile unsigned long *)0x4A000010)
    
/**
*如果不开启-O2以上优化,gcc编译器不提供inline优化,所以写入的inline只在编译时加入了-O2优化选项才会有效,这时for里面的循环参数可以不加volatile
*如果开启了-O2以上优化,gcc提供的inline优化有效,如果for循环里做编译器认为没意义的事,循环参数加上volatile声明。
*/

static inline void  delay(volatile unsigned long dly)
{
for(; dly > 0; dly--);

}

int  main()
{
    unsigned long i = 0;    
    delay(20000);
    if(INTOFFSET == 5){
        i = EINTPEND & ((0x01<<19)|(0x07<<13)|(0x01<<11)|(0x01<<8));
        switch(i)
        {
            case (0x01<<8):
                GPBDAT = GPBDAT^(1<<5);        //翻转LED1
                break;
            case (0x01<<11):
                GPBDAT = GPBDAT^(1<<6);        //翻转LED2
                break;
            case (0x01<<13):
                GPBDAT = GPBDAT^(1<<7);        //翻转LED3
                break;
            case (0x01<<14):
                GPBDAT = GPBDAT^(1<<8);        //翻转LED4
                break;
            case (0x01<<15):
                GPBDAT &= ~(0x0f<<5);        //灯全亮
                break;
            case (0x01<<19):
                GPBDAT |= (0x0f<<5);        //灯全灭
                break;
            default:
                break;
        }    
    }

    EINTPEND = EINTPEND;    //这个要先清除,不然处理器还是会以为产生外部中断
    SRCPND = SRCPND;
    INTPND = INTPND;
    return 0;
}




你可能感兴趣的:(六、mini2440裸机程序之中断控制器(2)外部按键中断)