ATIME

嵌入式裸机程序之中断原理

1.中断简介

中断,指计算机运行过程中,出现异常后,计算机停止当前工作保存当前状态,然后转向对这些异常的处理,在处理完成后再返回到停止时的状态,继续运行。
《嵌入式裸机程序之中断原理》

2.S3C2440中断

S3C2440有60个中断源,这里只以其中的外部中断为例,以最简单的中断处理过程代码来分析中断。
中断处理之前需要先将各个IO引脚设置为中断功能,将指示灯的IO引脚设置为输出模式。在此之后,需要了解S3C2440的各组中断的指针位置。
如代码所示,在这段汇编代码中定义了各个中断的入口,本实验使用HandleIRQ这个入口地址,当出现中断信号时,程序跳转到0x18这个地址,然后再跳转到HandleIRQ这个函数。
HandleIRQ函数首先将当前寄存器状态入栈保存,然后再跳转到真正的中断服务程序。
在中断服务程序中,根据INTOFFSET寄存器的内容来做出相应的指示,在完成中断响应后需要手动清中断。
这样主程序不需要运行其他代码,中断的初始化、IO接口初始化也都在汇编文件中完成。
@******************************************************************************
@ File:head.S
@ 功能:初始化,设置中断模式、管理模式的栈,设置好中断处理函数
@******************************************************************************       
   
.extern     main
.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       @ 进入中断模式
    ldr sp, =3072           @ 设置中断模式栈指针

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

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

中断服务程序:
#include "s3c2440.h"

void EINT_Handle()
{
    unsigned long oft = INTOFFSET;
    unsigned long val;

	/*
	 * K1,K2,K3,K4对应GPF1、GPF4、GPF2、GPF0
	 *            即 EINT1, ETIN4, EINT2, EINT0
	 *            oft为 1, 4, 2, 0 (对应INTMSK寄存器)
	 */
    
    switch( oft )
    {
        // K1被按下
        case 1: 
        {   
            GPBDAT |= (0xF<<5);   // 所有LED熄灭
            GPBDAT &= ~(1<<5);      // LED1点亮
            break;
        }
        
        // K2被按下
        case 4:
        {   
            GPBDAT |= (0xF<<5);   // 所有LED熄灭
            GPBDAT &= ~(1<<6);      // LED2点亮
            break;
        }

        // K3被按下
        case 2:
        {   
            GPBDAT |= (0xF<<5);   // 所有LED熄灭
            GPBDAT &= ~(1<<7);      // LED3点亮
            break;
        }

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

        default:
            break;
    }

    //清中断
    if( oft == 4 ) 
        EINTPEND = (1<<4);   // EINT4_7合用IRQ4
    SRCPND = 1<<oft;
    INTPND = 1<<oft;
}





点赞