S5PV210中断系统
来源:互联网 发布:生化危机6mac 编辑:程序博客网 时间:2024/05/21 22:40
中断实现机制:异常向量表
1、中断是指CPU在执行程序的过程中,遇到异常情况需要处理,CPU就会中断当前的程序,保存当前程序运行处的必要参数,跳去执行异常程序,处理结束后再返回之前程序的间断处,继续执行原程序。
2、异常向量表是CPU中某些特定地址的特定定义,当中断发生时会去该向量表查询对应的异常事件,并处理该事件,完成后返回。
3、对于SOC来说,发生复位、软中断、中断、快速中断、取指令异常、数据异常等,我们都统一叫异常,所以说:中断其实是异常的一种。
4、S5PV210的异常向量表可以改变(在CP15协处理器中),以适应操作系统的需求。但是系统刚启动的时候,DRAM还没初始化,程序都在SRAM中运行。所以S5PV210在IRAM中设置异常向量表,供暂时使用。iRAM中的异常向量表起始地址为0xD0037400。
5、函数名的实质就是函数的首地址,当我们将异常处理程序的首地址和异常向量表绑定起来后,可以保证相应异常发生后,硬件自动跳转到对应异常向量表入口去执行时,可以执行到我们事先绑定的函数。
汇编保存现场和恢复现场
中断去执行异常程序时,要先保护现场和恢复现场。保护现场:中断从SVC模式来,则需要保存SVC模式下必要寄存器的值。恢复现场:中断处理完成后,要返回SVC模式时,将之前SVC模式保存的寄存器恢复回去,以免程序错乱。保存现场包括--->第一:设置IRQ栈;第二,保存LR;第三,保存R0~R12。
为什么要保存LR寄存器?
要考虑中断返回的问题。中断ISR执行完后如何返回SVC模式下去接着执行原来的代码。中断返回其实取决于我们进入中断时如何保存现场。中断返回时关键的2个寄存器就是PC和CPSR。所以我们在进入IRQ模式时,应该将SVC模式下的下一句指令的地址(中断返回地址)和CPSR保存起来,将来恢复时才可以将中断返回地址给PC,将保存的SPSR给CPSR。中断返回地址保存在LR中,CPSR保存在IRQ模式下的SPSR中。保护现场关键是保存:中断处理程序的返回地址,r0-r12(cpsr是自动保存的),恢复现场主要是恢复:r0-r12,pc,cpsr。
S5PV210的向量中断过程
异常可分为两个阶段来理解。第一个阶段是异常向量表跳转;第二个阶段就是进入了真正的异常处理程序irq_handler之后的部分。第一个阶段主要依赖CUP提供的向量表机制,主要的任务是从异常发生到响应异常并且保存和恢复现场。第二个任务目的是识别是哪个中断源,然后调用相应的处理程序来处理这个中断。
S5PV210与中断有关的寄存器
1、VICnINTENABLE
负责相应的中断的使能。当我们想使能某个中断时,只要在这个中断编号对应的VICnINTENABLE相应位写1就可以。
2、VICnINTENCLEAR
当我们执行完中断处理程序后,应当清除中断标志位,下次再次中断时才能进入。有些CPU是中断使能和禁止是一个寄存器位,写1就使能写0就进制(或者反过来写1就进制写0就使能)
3、VICnINTSELECT
设置各个中断的模式为irq还是fiq。
1.IRQ和FIQ的区别?210中支持2种中断,irq和fiq。irq是普通中断,fiq是快速中断。快速中断是一种更快响应处理的中断通道,用于对实时性要求很高的中断源。fiq在CPU设计时预先提供了一些机制保证fiq可以被快速处理,从而保证实时性。fiq的限制就是只能有一个中断源被设置为fiq,其他都是irq。
2.CPU如何保证fiq比irq快?有2个原因:第一,fiq模式有专用的r8~r12,因此在fiq的isr中可以直接使用r8-r12而不用保存,这就能节省时间;第二,异常向量表中fiq是最后一个异常向量入口。因此fiq的isr不需要跳转,可以直接写在原地,这样就比其他异常少跳转一次,省了些时间。
4、VICnIRQSTATUS和VICnFIQSTATUS
只读的状态寄存器,当发生中断时,硬件自动将该寄存器对应的位置为1,表明中断发生。
5、VICVECTPRIORITY
中断优先级设置寄存器,设置多个中断同时发生时先处理谁后处理谁的问题,可支持中断嵌套。
VICnVECTADDR0到31这32个寄存器分别用来存放真正的各个中断对应的isr的函数地址。相当于每一个中断源都有一个VECTADDR寄存器,设置中断的时候,把这个中断的isr地址直接放入这个中断对应的VECTADDR寄存器即可。VICnADDR这个寄存器是只需要读的,它里面的内容是由硬件自动设置的,当发生了相应中断时,硬件会自动识别中断编号,并且会自动找到这个中断的VECTADDR寄存器,然后将其读出复制到VICnADDR中,供我们使用。
Start.s文件
#define SVC_STACK 0xd0037d80
#define IRQ_STACK 0xd0037f80
.global _start
.global IRQ_handle
_start:
bl clock_init //初始化时钟
ldr sp, = SVC_STACK //设置SVC栈
/* 开/关icache */
mrc p15,0,r0,c1,c0,0;//读出cp15的c1到r0中
//bic r0, r0, #(1<<12)// bit12置0 关icache
orr r0, r0, #(1<<12)// bit12 置1 开icache
mcr p15,0,r0,c1,c0,0;
bl main
//bl led_blink
b .
// 在这个汇编函数中,用来做中断模式下的现场保护和恢复,并且调用真正的中断处理程序
IRQ_handle:
ldr sp, = IRQ_STACK //设置IRQ模式下的栈
// 保存LR,因为ARM有流水线,所以PC的值会比真正执行的代码+8
sub lr, lr, #4
// 保存r0-r12和lr到irq模式下的栈上面
stmfd sp!, {r0-r12, lr}
// 在此调用真正的isr来处理中断
bl irq_handler
// 处理完成开始恢复现场(做中断返回),将r0-r12,pc,cpsr一起返回。
ldmfd sp!, {r0-r12, pc}^
/*********以下对应的寄存器宏定义没写上来,可查看手册**********/
void key_init_interrupt(void)
{
// 1. 外部中断对应的GPIO模式设置
rGPH0CON |= 0xFF<<8;// GPH0_2 GPH0_3设置为外部中断模式
rGPH2CON |= 0xFFFF<<0;// GPH2_0123共4个引脚设置为外部中断模式
// 2. 中断触发模式设置
rEXT_INT_0_CON &= ~(0xFF<<8); // bit8~bit15全部清零
// EXT_INT2和EXT_INT3设置为下降沿触发
rEXT_INT_0_CON |= ((2<<8)|(2<<12));
rEXT_INT_2_CON &= ~(0xFFFF<<0);
rEXT_INT_2_CON |= ((2<<0)|(2<<4)|(2<<8)|(2<<12));
// 3. 中断允许
rEXT_INT_0_MASK &= ~(3<<2);//外部中断允许
rEXT_INT_2_MASK &= ~(0x0f<<0);
// 4. 清挂起,清除是写1,不是写0
rEXT_INT_0_PEND |= (3<<2);
rEXT_INT_2_PEND |= (0x0F<<0);
}
void intc_init(void)
{
//禁止所有中断
VIC0INTENCLEAR = 0xffffffff;
VIC1INTENCLEAR =0xffffffff;
VIC2INTENCLEAR =0xffffffff;
VIC3INTENCLEAR =0xffffffff;
//选择中断类型为IRQ
VIC0INTSELECT = 0x0;
VIC1INTSELECT = 0x0;
VIC2INTSELECT = 0x0;
VIC3INTSELECT = 0x0;
//清VICxADDR
intc_clearvectaddr();
}
//绑定异常向量表;禁止所有中断;选择所有中断类型为IRQ;清除VICnADDR为0
void system_init_exception(void)
{
// 绑定异常向量表
r_exception_reset = (unsigned int)reset_exception;
r_exception_undef = (unsigned int)undef_exception;
r_exception_sotf_int = (unsigned int)sotf_int_exception;
r_exception_prefetch = (unsigned int)prefetch_exception;
r_exception_data = (unsigned int)data_exception;
r_exception_irq = (unsigned int)IRQ_handle;
r_exception_fiq = (unsigned int)IRQ_handle;
// 初始化中断控制器的基本寄存器
intc_init();
}
// 清除需要处理的中断的中断处理函数的地址
void intc_clearvectaddr(void)
{
// VICxADDR:当前正在处理的中断的中断处理函数的地址
VIC0ADDR = 0;
VIC1ADDR = 0;
VIC2ADDR = 0;
VIC3ADDR = 0;
}
// 通过读取VICnIRQSTATUS寄存器,判断其中哪个有一位为1,可知哪个VIC发生中断了
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)
return VIC3IRQSTATUS;
else
{}
return0;
}
//寻找对应中断处理程序
void irq_handler(void)
{
/*此函数是检查是哪一个VIC的中断,就是isr对应在哪个VICADDR寄存器
中,然后调用对应中断isr*/
unsigned long vicaddr[4] = {VIC0ADDR,VIC1ADDR,VIC2ADDR,VIC3ADDR};
inti = 0;
void(*isr)(void) = NULL;
for(i=0; i<4; i++)
{
// 发生一个中断时,4个VIC中有3个是全0,1个的其中一位不是0
if(intc_getvicirqstatus(i) !=0)
{
isr = (void (*)(void)) vicaddr[i];
break;
}
}
(*isr)();//通过函数指针来调用函数
}
//中断服务函数
void isr_eint2(void)
{
printf("isr_eint2_LEFT.\n");
rEXT_INT_0_PEND |= (1<<2); //清除中断挂起
intc_clearvectaddr();
}
void isr_eint3(void)
{
printf("isr_eint3_DOWN.\n");
rEXT_INT_0_PEND |= (1<<3);
intc_clearvectaddr();
}
void isr_eint16171819(void)
{
if (rEXT_INT_2_PEND & (1<<0))
{
printf("eint16\n");
}
rEXT_INT_2_PEND |= (0x0f<<0);
intc_clearvectaddr();
}
void intc_setvectaddr(unsigned long intnum,void (*handler)(void)) {
if(intnum<32) { //VIC0
*( (volatile unsigned long *)(VIC0VECTADDR +4*(intnum-0)) ) =
(unsigned)handler;
}
else if(intnum<64) { //VIC1
*( (volatile unsigned long *)(VIC1VECTADDR +4*(intnum-32)) ) =
(unsigned)handler;
}
else if(intnum<96) { //VIC2
*( (volatile unsigned long *)(VIC2VECTADDR +4*(intnum-64)) ) =
(unsigned)handler;
}
else { //VIC3
*( (volatile unsigned long*)(VIC3VECTADDR + 4*(intnum-96)) ) =
(unsigned)handler;
}
return;
}
// 读取VICnIRQSTATUS寄存器,判断其中哪个为1,可知哪个VIC发生中断了
unsigned long intc_getvicirqstatus(unsigned long ucontroller)
{
if(ucontroller ==0)
return VIC0IRQSTATUS;
else if(ucontroller ==1)
return VIC1IRQSTATUS;
else if(ucontroller ==2)
return VIC2IRQSTATUS;
else if(ucontroller ==3)
return VIC3IRQSTATUS;
else
{}
return0;
}
- S5PV210中断系统
- GEC210(S5PV210)裸机驱动之中断系统
- s5pv210——中断系统相关介绍
- 十.ARM裸机学习之中断系统2(S5PV210按键外部中断及中断处理)
- 十.ARM裸机学习之中断系统1(S5PV210的中断系统详解)
- wince6.0 s5pv210 中断
- linux中断之一(s5pv210)
- wince6.0 s5pv210 中断
- S5PV210——中断
- s5pv210的汇编中断
- S5PV210中断配置
- S5PV210中断体系
- s5pv210中断体系
- S5PV210的中断编程
- S5PV210外部中断
- s5pv210的中断源
- s5pv210 中断学习笔记
- S5PV210 input中断输入驱动
- 十一个行为型模式1:职责链模式-Chain of Responsibility Pattern【学习难度:★★★☆☆,使用频率:★★☆☆☆】
- express取参数req.query, req.params, req.body方法如何使用
- Tensorflow 学习笔记- tensor的声明
- OpenGL的第一天【VS2017+OpenGL环境的配置】
- ServletContextListener
- S5PV210中断系统
- Lintcode125 Backpack ||solution 题解
- poj 1459 Power Network
- Redux讲解
- JSONP是什么
- 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 F island
- HDU 2594 Simpsons’ Hidden Talents 两字符串前缀与后缀的最长公共部分
- 《PID控制算法的C语言实现》学习笔记
- 哈哈日语 学渣的日语N1失败经验谈