知识点
1、中断的概念
2、中断源
3、中断过滤
4、中断处理

中断:

cpu在工作的过程中经常需要与外设进行交互,交互的方式包括轮询方式和中断方式。

轮询方式:

cpu不断地查询设备的状态,该方式实现简单,但是cpu消耗大。

中断方式:

CPU在告知硬件开始一项工作后,就调度到其他事情了,当该硬件完成该事件后,会向CPU发送信号,告知CPU它已经完成了该项工作。实际上是cpu有一个状态寄存器,每次执行指令的时候会检查状态寄存器的值。CPU接收到中断信号时,CPU会立即进入到中断模式。

中断的生命周期:

中断信号产生(中断源)---> 中断信号过滤(中断控制器)--->中断信号处理(CPU)

中断源:

在中断生命周期中,中断源的作用是负责产生中断信号,每个cpu支持的中断源数量是不同的。
s3c2440支持60个中断源
s5pv210支持93个中断源

中断过滤:

 

 

 

 

 

 代码分析

start.S

.text
.global _start
_start:
    b reset
    ldr pc, _undifined_instruction
    ldr pc, _software_interrupt
    ldr pc, _prefetch_abort
    ldr pc, _data_abort
    ldr pc, _not_used
    ldr pc, _irq
    ldr pc, _fiq
    

_undifined_instruction: .word undifined_instruction
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_data_abort: .word data_abort
_not_used: .word not_used
_irq: .word irq
_fiq: .word reset

undifined_instruction:
    nop

software_interrupt:
    nop
    
prefetch_abort:
    nop
    
data_abort:
    nop

not_used:
    nop

irq:
    sub lr, lr, #4  
    stmfd sp!, {r0-r12, lr}     /* 保护现场 */  
    bl handle_int               
    ldmfd sp!, {r0-r12, pc}^    /* 恢复现场,^表示把spsr恢复到cpsr */  
    
fiq:    
    nop

reset:
    bl set_svc
    bl disable_watchdog
    bl disable_interrupt
    bl disable_mmu
    bl init_clock
    bl init_sdram
    bl copy_to_ram
    bl init_stack
    bl clean_bss
    ldr pc, =gboot_main
@    bl light_led

set_svc:
    mrs r0, cpsr
    bic r0, r0,#0x1f
    orr r0, r0,#0xd3
    msr cpsr, r0
    mov pc, lr

#define pWTCON 0x53000000
disable_watchdog:
    ldr r0, =pWTCON
    mov r1, #0x0
    str r1, [r0]
    mov pc, lr

disable_interrupt:
    mvn r1, #0x0
    ldr r0, =0x4a000008
    str r1, [r0]
    mov pc, lr
    
disable_mmu:
    mcr p15,0,r0,c7,c7,0
    mrc p15,0,r0,c1,c0,0
    bic r0, r0, #0x00000007
    mcr p15,0,r0,c1,c0,0
    mov pc, lr

#define CLKDIVN 0x4c000014
#define MPLLCON 0x4c000008
#define MPLL_405MHZ ((127<<12)|(2<<4)|(1<<0))

init_clock:
    ldr r0, =CLKDIVN
    mov r1, #0x5
    str r1, [r0]
    
    mcr p15,0,r0,c1,c0,0
    orr r0,r0,#0xc0000000
    mcr p15,0,r0,c1,c0,0
    
    ldr r0, =MPLLCON
    ldr r1, =MPLL_405MHZ
    str r1, [r0]
    mov pc, lr
    
#define mem_contrl 0x48000000
init_sdram:
    ldr r0, =mem_contrl 
    add r3, r0, #4*13
    adrl r1, mem_data

0:
    ldr r2, [r1], #4
    str r2, [r0], #4
    cmp r0, r3
    bne 0b
    mov pc, lr
    
copy_to_ram:
    ldr r0, =0x0
    ldr r1, =0x30008000
    add r3, r0, #1024*4

copy_loop:
    ldr r2, [r0], #4
    str r2, [r1], #4
    cmp r0, r3
    bne copy_loop
    mov pc, lr
    
init_stack:
    msr cpsr_c, #0xd2
    ldr sp, =0x33000000    @此处实际设置的是r13_irq            
    msr cpsr_c, #0xd3
    ldr sp, =0x34000000    @此处实际设置的是r13_svc
    mov pc, lr

clean_bss:
    ldr r0, =bss_start
    ldr r1, =bss_end
    cmp r0, r1
    moveq pc, lr

clean_loop:
    mov r2, #0
    str r2, [r0], #4
    cmp r0, r1
    bne clean_loop
    mov pc, lr

mem_data:
    .long 0x22000000 
    .long 0x00000700
    .long 0x00000700
    .long 0x00000700
    .long 0x00000700
    .long 0x00000700
    .long 0x00000700
    .long 0x00018001
    .long 0x00018001
    .long 0x008c04f5
    .long 0x000000b1
    .long 0x00000030
    .long 0x00000030

#define GPBCON 0x56000010
#define GPBDAT 0x56000014
light_led:
    ldr r0, =GPBCON
    ldr r1,=0x15400
    str r1, [r0]
    
    ldr r0, =GPBDAT
    ldr r1,=0x6BF
    str r1, [r0]
    mov pc, lr

interrupt.c

/*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

#define EINTMASK            (volatile unsigned long *)0x560000a4
#define EINTPEND            (volatile unsigned long *)0x560000a8

void init_irq()
{

    // 对于EINT4,需要在EINTMASK寄存器中使能它
    *(EINTMASK) &= ~(1<<4);
            

    // EINT0、EINT1、EINT2、EINT4_7使能
    *(INTMSK)   &= (~(1<<0)) & (~(1<<1)) & (~(1<<2)) & (~(1<<4));
    
    __asm__( 
    /*开中断*/  
    "mrs r0,cpsr\n"
    "bic r0, r0, #0x80\n"
    "msr cpsr_c, r0\n"            
    : 
    : 
  );
}

void handle_int()
{
    /*读取产生中断的源*/
    unsigned long value = *(INTOFFSET);  //*(INTOFFSET)就可以直接过去中断源
    
    switch(value) 
    {
        case 0: //EINT0~K4
            led_on();
            break;
        
        case 1: //EINT1~K1
            led_off();
            break;
        
        case 2: //EINT2~K3
            led_on();
            break;
        
        case 4: //EINT4~K2
            led_off();
            break;
        
        default:
            break;
    }
    
    /* 中断清除 */
    if(value == 4)
    *(EINTPEND) = (1 << 4);
    *(SRCPND) = 1 << value;
    *(INTPND) = 1 << value;
}