[嵌入式]异常与中断(下)
来源:互联网 发布: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)();
}
- [嵌入式]异常与中断(下)
- [嵌入式]异常与中断(上)
- Linux下的中断与异常
- 中断与异常
- 3.中断与异常
- ARM异常与中断
- 中断与异常
- 关于中断与异常
- 中断与异常处理
- ARM7异常与中断
- 异常与中断处理
- 中断与异常
- mips下的异常、中断
- 中断分类(异常 与 中断)
- 【中断异常】软中断与Bottom Half
- 中断与异常的关系
- 中断与异常的区别
- 异常与中断的区别
- ubuntu14.0.4 LTS install sougoupinyin input method
- ListView的Adapter优化
- neutron server启动流程
- hibernate实体对象的三种状态:自由状态,持久状态,游离状态.
- 【hi3516a 调试笔记】 海思hi3516a平台音频aac编码测试
- [嵌入式]异常与中断(下)
- Templates模板使用?
- 实型变量
- 配置描述符web.xml
- 兼容IE跨平台解决方案
- 【双拼】双拼输入法入门指南
- 时间紧、任务重的时候怎么办,怎么解决还未完成的代码?
- 448. Find All Numbers Disappeared in an Array
- 简单的JavaWeb投票系统