s3c2440中断体系结构

一、arm异常工作模式介绍

page73

arm920T共有7种工作模式,共有31个通用的32位寄存器和6个程序状态寄存器(cpsr),共37个。其中标注三角的对应模式下特有的寄存器,其中cpsr控制工作模式。

page76

N:结果是否为负数           Z:计算结果是否为0     C:进位/借位/移位溢出  V:溢出标志

I:中断禁止位(1禁止中断,0允许)                     F:快中断禁止位(1禁止中断,0允许)            T:cpu状态位(arm与THUMB)    M0~M4:工作模式位

注意:不能直接设置T位,否则会发生不可预知的问题

工作模式位:

page78

当一个异常发生时,ARM920T 将完成:

1.在异常模式的lr(r14)中保存前一个工作模式的下一条,即将执行的指令地址,如下图。

2.cpsr复制到spsr。

3.设置cpsr工作模式位为要进入的异常工作状态。

4.将pc指针指向异常向量表。

如果要返回原来的工作模式,则:

1.将lr中的值减去适当的的值给pc

2.将spsr的值赋值给cpsr。

page80

page82

ARM920T一上电处于arm状态,并工作与管理模式(svc),并把pc指针赋值为0.

二、中断控制器介绍

基本工作流程:

page378

寄存器介绍:

(1)源等待寄存器

page384

读:为1表明有中断发生,0没有                  写:1清除已经发生的中断,0无效

(2)中断模式寄存器

设置对应位为0处于IRQ模式,为1处于FIQ模式

(3)中断屏蔽寄存器

对应位为1屏蔽该中断,0激活该中断

(4)优先级寄存器

优先级的判断由6个一级仲裁器和一个二级仲裁器组成,每个仲裁器能仲裁REQ0~REQ5(如下图)。

page382

优先级寄存器的ARB_SELx用于选择中断的优先级顺序,REQ0和REQ5的顺序不能改变,标号小的优先级高。

ARB_MODEx选择仲裁器工作模式,为0时按照ARB_SELx配置工作,为1时按照被服务的REQx自动变化,例如REQ1发生中断,那么ARB_SELx自动变成01

(5)中断等待寄存器

page391

一个中断没有被屏蔽,发生的时候相应的位会自动置1,否则为0。我们要在清除SRCPND相应的位之后清除相应的INTPND相应的位,写1清除,0无效。

(6)中断偏移寄存器

表示INTPND中的哪位被置一了,例如INTPND第10被置1,则INTOFFSET的值为10,清除了SRCPND和INTPND,INTOFFSET自动被清除

寄存器配置大概流程:


使用中断步骤:

1.设置中断模式下的堆栈,即给中断模式下的sp指针赋值,最好在cpsr中将中断屏蔽。

2.设置中断异常向量(addr=0x18)跳转函数,在函数中确定中断源进行处理,读INTOFFSET即可判断。然后清除中断,从源头先清,例如先清EINTPEND,然后SRCPND,最后清除INTPND。

3.进入中断模式保护现场,退出中断模式还原现场。

进入:sub lr, lr, #4
            stmdb sp!, {r0-r12,lr}

退出:ldmia sp!, {r0-r12,pc}^

4.设置具体引脚的模式,触发条件,是否被屏蔽等,在gpio那一章节。

5.确定中断方式为irq还是fiq,即配置INTMOD。

6.配置INMSK寄存器。

7.在cpsr中开启总中断。


实现同按不同的按键是led亮和灭

代码:

head.S

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

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

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

@ 0x14: 保留
HandleNotUsed:
    b   HandleNotUsed

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

@ 0x1c: 快中断模式的向量地址
HandleFIQ:
    b   HandleFIQ
 
rest:
    mov sp, #4096
    bl disable_watch_dog
    msr cpsr_c, #0xd2            @进入irq模式并屏蔽总中断
    mov sp, #3072                @设置irq模式下的堆栈
    
    msr cpsr_c, #0xd3            @进入管理模式
    bl init_led                    @初始化led
    bl init_irq                    @初始化irq
    msr cpsr_c, #0x53            @开启总中断
    bl main
halt_loop:
    b halt_loop
    
interrupt_server:
    sub lr, lr, #4
    stmdb sp!, {r0-r12,lr}
    ldr lr, =return
    ldr pc, =interrupt_handle
return:
    ldmia sp!, {r0-r12,pc}^    @^代表将spsr的值赋值给cpsr

init.c

#include "s3c2440.h"

#define GPF_EINT0  1<<1
#define GPF_EINT0_MASK  (~(3))
#define GPF_EINT2  1<<5
#define GPF_EINT2_MASK  (~(3 << 4))
#define GPG_EINT11 1<<7
#define GPG_EINT11_MASK (~(3 << 6))
#define GPF4_OUT  1<<8
#define GPF4_OUT_MASK (~(0X03 << 8))
#define GPF5_OUT  1<<10
#define GPF5_OUT_MASK (~(0X03 << 10))
#define GPF6_OUT  1<<12
#define GPF6_OUT_MASK (~(0X03 << 12))

void disable_watch_dog(void)
{
    WTCON = 0X00;
}


void init_led(void)
{
    //设置gpf4、5、6为输出
    GPFCON &= (GPF4_OUT_MASK & GPF5_OUT_MASK & GPF6_OUT_MASK);
    GPFCON |= (GPF4_OUT | GPF5_OUT | GPF6_OUT);
    GPFDAT |= (1<<4 | 1<<5 | 1<<6);
}

void init_irq(void)
{
    //gpf0、gpf2、gpg3设置为中断模式,默认为低电平触发
    GPFCON &= (GPF_EINT0_MASK & GPF_EINT2_MASK);
    GPFCON |= (GPF_EINT0 | GPF_EINT2);
    GPGCON &= GPG_EINT11_MASK;
    GPGCON |= GPG_EINT11;
    EINTMASK &= ~(1<<11);   //使能EINT11
    INTMOD &= (~1 & ~(1<<2) & ~(1<<5));        //irq模式
    INTMSK &= (~1 & ~(1<<2) & ~(1<<5));        //开启相应的中断
}

interrupt.c

#include "s3c2440.h"
void interrupt_handle()
{
    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
    SRCPND = 1<<oft;
    INTPND = 1<<oft;
}

main.c

int main()
{
    while(1);
    return 0;
}

Makefile:

objs := head.o init.o interrupt.o main.o

int.bin: $(objs)
    arm-linux-ld -Ttext 0x00000000 -o int_elf $^
    arm-linux-objcopy -O binary -S int_elf $@
    arm-linux-objdump -D -m arm int_elf > int.dis
    
%.o:%.c
    arm-linux-gcc -Wall -O2 -c -o $@ $<

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

clean:
    rm -f int.bin int_elf int.dis *.o        
   
s3c2440.h

/* WOTCH DOG register */
#define     WTCON           (*(volatile unsigned long *)0x53000000)

/*GPIO registers*/
#define GPFCON              (*(volatile unsigned long *)0x56000050)
#define GPFDAT              (*(volatile unsigned long *)0x56000054)
#define GPGCON              (*(volatile unsigned long *)0x56000060)
#define GPGDAT              (*(volatile unsigned long *)0x56000064)

/*interrupt registes*/
#define SRCPND              (*(volatile unsigned long *)0x4A000000)
#define INTMOD              (*(volatile unsigned long *)0x4A000004)
#define INTMSK              (*(volatile unsigned long *)0x4A000008)
#define PRIORITY            (*(volatile unsigned long *)0x4A00000c)
#define INTPND              (*(volatile unsigned long *)0x4A000010)
#define INTOFFSET           (*(volatile unsigned long *)0x4A000014)
#define SUBSRCPND           (*(volatile unsigned long *)0x4A000018)
#define INTSUBMSK           (*(volatile unsigned long *)0x4A00001c)

/*external interrupt registers*/
#define EINTMASK            (*(volatile unsigned long *)0x560000a4)
#define EINTPEND            (*(volatile unsigned long *)0x560000a8)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值