[嵌入式]异常与中断(下)

来源:互联网 发布:springmvc 项目源码 编辑:程序博客网 时间:2024/04/30 08:33
异常与中断

6.5  S5PV210的中断编程

中断跳转流程

    ARM处理器响应中断的时候,总是从固定的中断异常向量取地址开始的,而在高级语言环境下开发中断服务程序时,无法控制从固定地址处开始至中断服务程序的跳转流程。为了使得上层应用程序与硬件中断跳转联系起来,需要编写一段中间的服务程序来进行连接。这样的服务程序常被称作中断解析程序。

    每个异常向量对应一个4字节的空间,正好放置一条跳转指令或者向PC寄存器赋值的数据访问指令。具体中断跳转流程如图。

 

 

中断编程步骤

·建立系统中断向量表,设置微处理器内核的程序状态寄存器CPSR中的F位和I位。一般

  情况下中断均需使用数据栈,因此还需建立用户数据栈。这一部分内容对应的程序指令,

  通常编写在系统引导程序中。

·设置各中断源的中断向量。通常需要利用向量地址寄存器来计算,若中断号还对应有子中

  断,需求出子中断地址偏移。

·中断控制初始化。主要是初始化微处理器内部的中断控制的寄存器。针对某个具体的中断

  源,设置其中断控制模式、中断是否屏蔽、中断优先级等。

·完成I/O端口或部件具体操作功能的中断服务程序。中断服务程序中,在返回之前必须清

  除现场,返回中断前的状态。

中断示例硬件电路

   S5PV210 共支持 93 个中断源,这里将使能其中的八个外部中断。该示例通过中断XEINT16-XEINT27连接八只独立按键,响应按键动作,驱动蜂鸣器鸣响和相应的LED灯亮。其中一只按键电路和蜂鸣器电路如图。

 

start.S 汇编启动代码

.text

.global _start

.global irq_handler

_start:

breset

ldrpc,_undefined_instruction

ldrpc,_software_interrupt

ldrpc,_prefetch_abort

ldrpc,_data_abort

ldrpc,_not_used

ldrpc,_irq

ldrpc,_fiq

_undefined_instruction: .word  _undefined_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  _fiq

reset:

mrsr0,cpsr

bicr0,r0,#0x1f

orrr0,r0,#0xd3

msrcpsr,r0

init_stack:

ldrr0,stacktop

/********svc mode stack********/

movsp,r0

subr0,#128*4          //

/****irq mode stack**/

msrcpsr,#0xd2

movsp,r0

subr0,#128*4

/***fiq mode stack***/

msrcpsr,#0xd1

movsp,r0

subr0,#0

/***abort mode stack***/

msrcpsr,#0xd7

movsp,r0

subr0,#0

/***undefine mode stack***/

msrcpsr,#0xdb

movsp,r0

subr0,#0

 /*** sys mode and usr mode stack ***/

msrcpsr,#0x10

movsp,r0bmain

.align5

irq_handler:

sub  lr,lr,#4

stmfd sp!,{r0-r12,lr}

bldo_irq

ldmfd sp!,{r0-r12,pc}^

stacktop:    .wordstack+4*512

.data

 

Stack:.space4*512

 

main.c 源代码

#include "lib\stdio.h"

#include "int.h"

#define    GPH2CON(*(volatile unsigned long *) 0xE0200C40)

#define   GPH2DAT(*(volatile unsigned long *) 0xE0200C44)

#define   GPH2_0_EINT16(0xf<<(0*4))

#define   GPH2_1_EINT17(0xf<<(1*4))

#define   GPH2_2_EINT18(0xf<<(2*4))

#define   GPH2_3_EINT19(0xf<<(3*4))

#defineEXT_INT_0_CON  ( *((volatile unsigned long *)0xE0200E00) )

#defineEXT_INT_1_CON  ( *((volatile unsigned long *)0xE0200E04) )

#defineEXT_INT_2_CON  ( *((volatile unsigned long *)0xE0200E08) )

#defineEXT_INT_3_CON  ( *((volatile unsigned long *)0xE0200E0C) )

#defineEXT_INT_0_MASK   ( *((volatile unsigned long *)0xE0200F00) )

#defineEXT_INT_1_MASK   ( *((volatile unsigned long *)0xE0200F04) )

#defineEXT_INT_2_MASK  ( *((volatile unsigned long *)0xE0200F08) )

#defineEXT_INT_3_MASK   ( *((volatile unsigned long *)0xE0200F0C) )

#defineEXT_INT_0_PEND   ( *((volatile unsigned long *)0xE0200F40) )

……(以下寄存器地址声明略)

void uart_init();

// 延时函数

void delay(unsigned long count)

{

volatile unsigned long i = count;   

while (i--);    

}

 

void isr_key(void)

{

printf("we get company:EINT16_31\r\n");

intc_clearvectaddr(); // clear VIC0ADDR

EXT_INT_2_PEND |= 1<<0;// clear pending bit

}

int main(void)

{

int c = 0;

uart_init(); // 初始化串口

system_initexception(); // 中断相关初始化printf("**************Int test *************** \r\n");

// 外部中断相关的设置

GPH2CON |= 0xF; // 1111 = EXT_INT[16]EXT_INT_2_CON |= 1<<1;// 010 = Falling edge triggeredEXT_INT_2_MASK &= ~(1<<0); // unmasked

// 设置中断EINT16_31的处理函数

intc_setvectaddr(NUM_EINT16_31, isr_key);

// 使能中断EINT16_31

intc_enable(NUM_EINT16_31);

while (1)

{   printf("%d\r\n",c++);

delay(0x100000);

}

}

int.c 源代码

#include "int.h"

#include "lib\stdio.h"

 

//// Interrupt

#define VIC0_BASE(0xF2000000)

#define VIC1_BASE(0xF2100000)

#define VIC2_BASE(0xF2200000)

#define VIC3_BASE(0xF2300000)

 

// VIC0

#defineVIC0IRQSTATUS(*((volatile unsigned long *)(VIC0_BASE + 0x00)) )

……(以下寄存器地址声明略)

 

void exceptionundef(void)

{printf("undefined instruction exception.\n");

while(1)  ;

}

……(以下未定义具体操作的异常处理程序略)

// 中断相关初始化

void system_initexception( void)

{    // 设置中断向量表

pExceptionUNDEF  =(unsigned long)exceptionundef;

pExceptionSWI  =(unsigned long)exceptionswi;

pExceptionPABORT  =(unsigned long)exceptionpabort;

pExceptionDABORT  =(unsigned long)exceptiondabort;

pExceptionIRQ  =(unsigned long)irq_handler;

pExceptionFIQ  =(unsigned long)irq_handler;

// 初始化中断控制器

intc_init();

}

// 初始化中断控制器

void intc_init(void)

{// 禁止所有中断

    VIC0INTENCLEAR = 0xffffffff;VIC1INTENCLEAR = 0xffffffff;

VIC2INTENCLEAR = 0xffffffff;VIC3INTENCLEAR = 0xffffffff;

// 选择中断类型为IRQ

VIC0INTSELECT = 0x0;VIC1INTSELECT = 0x0;

VIC2INTSELECT = 0x0;VIC3INTSELECT = 0x0;

// 清VICxADDR

intc_clearvectaddr();

}

// 保存需要处理的中断的中断处理函数的地址

void intc_setvectaddr(unsigned long intnum, void (*handler)(void))

{//VIC0

if(intnum<32)

{

*( (volatile unsigned long *)(VIC0VECTADDR + 4*intnum) ) = (unsigned)handler;

}

                  ……其他向量控制器程序略。

return;

}

 

// 清除需要处理的中断的中断处理函数的地址

void intc_clearvectaddr(void)

{// VICxADDR:当前正在处理的中断的中断处理函数的地址

VIC0ADDR = 0;

VIC1ADDR = 0;

VIC2ADDR = 0;

VIC3ADDR = 0;

}

// 使能中断

void intc_enable(unsigned long intnum)

{……具体程序略。}

 

// 禁止中断

void intc_disable(unsigned long intnum)

{……具体程序略。

 

// 读中断状态

unsigned long intc_getvicirqstatus(unsigned long ucontroller)

{if(ucontroller == 0)

returnVIC0IRQSTATUS;

else if(ucontroller == 1)

returnVIC1IRQSTATUS;

else if(ucontroller == 2)

returnVIC2IRQSTATUS;

else if(ucontroller == 3)

returnVIC3IRQSTATUS;

else    {}

return 0;

}

// 通用中断处理函数

void do_irq(void)

{

unsigned long vicaddr[4] = {VIC0ADDR,VIC1ADDR,VIC2ADDR,VIC3ADDR};

int i=0;

void (*isr)(void) = NULL;

for(; i<4; i++)

    {

if(intc_getvicirqstatus(i) != 0)

        {

isr = (void (*)(void)) vicaddr[i];

break;

        }

    }

    (*isr)();

}


0 0
原创粉丝点击