一、介绍

1、三星S5PV210中断体系介绍

异常向量表(矢量中断控制器)
异常向量表是CPU中某些特定地址的特定定义,当中断发生的时候,中断要通知CPU处理中断,在CPU设计时,定义了CPU中一些特定地址作为特定异常的入口地址,异常向量表的实现,是基于SoC内部的矢量中断控制器。关于矢量中断控制器的描述,这里摘录了网友“亦大乐谍“的博客:

S5PV210是三星推出的一款基于Cortex-A8的Soc,其内部集成的中断控制器由4个ARM PrimeCell
PL192矢量中断控制器级连(daisy-chain)而成,每个PL192 VIC(Vectored Interrupt
Controller)支持32个中断源,所以最多支持128个。S5PV210使用了其中的93个。所谓“矢量”是指当中断发生时,软件可以直接从VIC得到提前设好的中断服务程序ISR(Interrupt
Service Routine)。
CPU在对VIC进行初始化的过程中,将各个中断源的ISR写入到VIC中存储起来,在中断发生以后,VIC会自动挑选出当前优先级最高的中断源,并将其ISR推送到VICADDRESS寄存器里,CPU可以直接拿到ISR(一般就是一个函数的起始地址),将PC跳转到这个地址取执行就可以了,速度大大加快

以上讲的是CPU硬件设计时对异常向量表的支持,接下来就需要软件支持。硬件已近决定了的发送什么异常CPU自动跳转PC到那个地址执行,软件需要做的就是把处理这个异常的代码的收地孩子填入这个异常向量的地址。

二、异常处理的两个阶段

(1)第一个阶段之所以能够进行,主要依赖于CPU设计时提供的异常向量表机制。第一个阶段的主要任务是从异常发生到响应异常并且保存/恢复现场,跳转到真正的异常处理程序处。
(2)第二个阶段的目的是识别多个中断源中究竟是哪一个发生了中断,然后调用相应的中断处理程序来处理这个中断。

三、编程思路

整个中断的工作分为2部分:
第一部分是我们为中断响应的预备工作
1、初始化中断控制器
2、绑定写好的isr到中断控制器
3、相应的中断的所有条件的使能
第二部分是当硬件产生中断后如何自动执行isr
1、第一步,经过异常向量表跳转入IRQ/FIQ入口
2、第二步,做中断现场保护(在start.s),然后跳入isr_handler
3、第三步,在isr_handler中先去搞清楚是哪个VIC中断了,然后直接去VIC的ADDR寄存器中去isr来执行即可
4、第四步,isr执行完,中断现场恢复,直接返回继续做常规任务。

四、使用外部中断时需要配置的几个重要的寄存器

1、VIC0INTENABLE和VIC0INTENCLEAR

(1) VICnINTENABLE ------interrupt enable
VINTENCLEAR ------interrupt enable clear
(2)INTENABLE寄存器负责相应的中断的使能;INTENCLEAR寄存器负责相应的中断的禁止。
(3)当我们想使能(意思就是启用这个中断,意思就是当硬件产生中断时CPU能接收的到)某个中断时,只要在这个中断编号对应的VICnINTENABLE的相应bit位写1即可(注意这个位写1其他位写0对其他位没有影响);如果我们想禁止某个中断源时,只要向VICnINTENCLEAR中相应的位写1即可。注意:这里的设计一共有2种:有些CPU是中断使能和禁止是一个寄存器位,写1就使能写0就禁止(或者反过来写1就禁止写0就使能),这样的中断使能设计就要非常小心,要使用我们之前说过的读改写三部曲来操作;
另一种就是使能和禁止分开为2个寄存器,要使能就写使能寄存器,要禁止就写禁止寄存器。这样的好处是我们使能/禁止操作时不需要读改写,直接写即可。
2、VICnINTSELECT(Interrupt Select Register,中断模式选择寄存器,0选择IRQ ,1FIQ)

(1)设置各个中断的模式为irq还是fiq。一般都设置成irq
(2)IRQ和FIQ究竟的区别:
irq是普通中断,fiq是快速中断。快速中断提供一种更快响应处理的中断通道,用于对实时性要求很高的中断源。fiq在CPU设计时预先提供了一些机制保证fiq可以被快速处理,从而保证实时性。fiq的限制就是只能有一个中断源被设置为fiq,其他都是irq。
(3)CPU如何保证fiq比irq快?有2个原因:第一,fiq模式有专用的r8~r12,因此在fiq的isr中可以直接使用r8-r12而不用保存,这就能节省时间;第二,异常向量表中fiq是最后一个异常向量入口。因此fiq的isr不需要跳转,可以直接写在原地,这样就比其他异常少跳转一次,省了些时间。
3、VICnIRQSTATUS和VICnFIQSTATUS

中断状态寄存器,是只读的。当发生了中断时,硬件会自动将该寄存器的对应位置为1。
4、VICnVECTPRIORITY0~VICnVECTPRIORITY31

(1)中断优先级设置寄存器,设置多个中断同时发生时先处理谁后处理谁的问题。一般来说高优先级的中断可以打断低优先级的中断,从而嵌套处理中断。当然了有些硬件/软件可以设置不支持中断嵌套。
5、VICnVECTADDR0~VICnVECTADDR31、VICnADDR


(1)VICnVECTADDR0~31这32个寄存器分别用来存放真正的各个中断对应的isr的函数地址。相当于每一个中断源都有一个VECTADDR寄存器,程序员在设置中断的时候,把这个中断的isr地址直接放入这个中断对应的VECTADDR寄存器即可。
(2)VICnADDR这个寄存器是只需要读的,它里面的内容是由硬件自动设置的。当发生了相应中断时,硬件会自动识别中断编号,并且会自动找到这个中断的VECTADDR寄存器,然 后将其读出复制到VICnADDR中,供我们使用。这样的设计避免了软件查找中断源和isr,节省了时间,提高了210的中断响应速度。

五、代码分析

(一)代码分析—中断模式下的现场保护和恢复

IRQ_handle:

// 设置IRQ模式下的栈 0xD003_7F80

 ldr sp, =IRQ_STACK

// 保存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}^

(二)代码分析—从main函数中中断的相关函数入手拆解

 int main(void)
{int n = 0;uart_init();// 如果程序中要使用中断,就要调用中断初始化来初步初始化中断控制器system_init_exception();eint_init();// 绑定isr到中断控制器硬件intc_setvectaddr(KEY_DOWN, key_isr_eint2);intc_setvectaddr(KEY_BACK, key_isr_eint16171819);intc_enable(KEY_DOWN);intc_enable(KEY_BACK);while (1){printf("%d ", n++);delay(10000);}return 0;
}
  • ①代码:key_init_interrupt();

void key_init_interrupt(void)
{
//1、外部中断对应的GPIO模式设置
rGPH0CON |= 0xFF<<8; //GPH0_2和GPH0_3设置为外部中断模式
rGPH2CON |= 0XFFFF<<0; //GPH2_0,1,2,3共4个引脚设为外部中断模式
//2、中断触发模式设置,这里设为下降沿触发
EXT_INT_0_CON &= ~(0XFF<<8); //bit8~bit15全部清零
EXT_INT_0_CON |= ((2<<8)|(2<<12));//EXT_INT2和EXT_INT3设置位下降沿触发。
//3、 中断允许,清挂
rEXT_INT_0_MASK &= ~(3<<2);
rEXT_INT_2_MASK &= ~(3<<0x0f<<0);
//4、清挂起,清除是写1
rEXT_INT_0_PEND |= (3<<2);
rEXT_INT_2_PEND |= (0x0F<<0);
}

  • ②代码:System_init_exception();
    // 主要功能:绑定第一阶段异常向量表;禁止所有中断;选择所有中断类型为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_init(void)
    // 禁止所有中断
    // 为什么在中断初始化之初要禁止所有中断?
    // 因为中断一旦打开,因为外部或者硬件自己的原因产生中断后一定就会寻找isr
    // 而我们可能认为自己用不到这个中断就没有提供isr,这时它自动拿到的就是乱码
    // 则程序很可能跑飞,所以不用的中断一定要关掉。
    // 一般的做法是先全部关掉,然后再逐一打开自己感兴趣的中断。一旦打开就必须
    // 给这个中断提供相应的isr并绑定好。

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_clearvectaddr(void)
// 清除需要处理的中断的中断处理函数的地址
void intc_clearvectaddr(void)
{
// VICxADDR:当前正在处理的中断的中断处理函数的地址
VIC0ADDR = 0;
VIC1ADDR = 0;
VIC2ADDR = 0;
VIC3ADDR = 0;
}

  • ③ 代码:intc_setve

ctaddr(KEY_INT2, isr_eint2);
// 绑定isr到中断控制器硬件

 intc_setvectaddr(KEY_INT2, isr_eint2);intc_setvectaddr(KEY_INT3, isr_eint3);intc_setvectaddr(KEY_INT16_19, isr_eint16171819);// 绑定我们写的isr到VICnVECTADDR寄存器
// 绑定过之后我们就把isr地址交给硬件了,剩下的我们不用管了,硬件自己会处理
// 等发生相应中断的时候,我们直接到相应的VICnADDR中去取isr地址即可。
// 参数:intnum是int.h定义的物理中断号,handler是函数指针,就是我们写的isr
// VIC0VECTADDR定义为VIC0VECTADDR0寄存器的地址,就相当于是VIC0VECTADDR0~31这个
// 数组(这个数组就是一个函数指针数组)的首地址,然后具体计算每一个中断的时候
// 只需要首地址+偏移量即可。

void intc_setvectaddr(unsigned long intnum, void (*handler)(void))
{
//VIC0
if(intnum<32)
{
*( (volatile unsigned long )(VIC0VECTADDR + 4(intnum-0)) ) = (unsigned)handler;
}
//VIC1
else if(intnum<64)
{
*( (volatile unsigned long )(VIC1VECTADDR + 4(intnum-32)) ) = (unsigned)handler;
}
//VIC2
else if(intnum<96)
{
*( (volatile unsigned long )(VIC2VECTADDR + 4(intnum-64)) ) = (unsigned)handler;
}
//VIC3
else
{
*( (volatile unsigned long )(VIC3VECTADDR + 4(intnum-96)) ) = (unsigned)handler;
}
return;
}

  • ③代码:intc_ena

ble(KEY_DOWN);
// 使能中断
// 通过传参的intnum来使能某个具体的中断源,中断号在int.h中定义,是物理中断号

#define NUM_HSMMC3 (96+2)
#define NUM_CEC (96+3)
#define NUM_TSI (96+4)
#define NUM_MDNIE0 (96+5)
#define NUM_MDNIE1 (96+6)
#define NUM_MDNIE2 (96+7)
#define NUM_MDNIE3 (96+8)
#define NUM_ADC1 (96+9)
#define NUM_PENDN1 (96+10)
#define NUM_ALL (200)

void intc_enable(unsigned long intnum)
{
unsigned long temp;
// 确定intnum在哪个寄存器的哪一位
// <32就是0~31,必然在VIC0
if(intnum<32)
{
temp = VIC0INTENABLE;
temp |= (1<<intnum); // 如果是第一种设计则必须位操作,第二种设计可以
// 直接写。
VIC0INTENABLE = temp;
}
else if(intnum<64)
{
temp = VIC1INTENABLE;
temp |= (1<<(intnum-32));
VIC1INTENABLE = temp;
}
else if(intnum<96)
{
temp = VIC2INTENABLE;
temp |= (1<<(intnum-64));
VIC2INTENABLE = temp;
}
else if(intnum<NUM_ALL)
{
temp = VIC3INTENABLE;
temp |= (1<<(intnum-96));
VIC3INTENABLE = temp;
}
// NUM_ALL : enable all interrupt
else
{
VIC0INTENABLE = 0xFFFFFFFF;
VIC1INTENABLE = 0xFFFFFFFF;
VIC2INTENABLE = 0xFFFFFFFF;
VIC3INTENABLE = 0xFFFFFFFF;
}
}

S5PV210中断的介绍与配置相关推荐

  1. s5pv210——中断系统相关介绍

    以下内容源于朱有鹏课程的学习,如有侵权,请告知删除. 参考资料:http://www.cnblogs.com/biaohc/p/6354068.html 一.S5PV210的中断体系介绍 1.什么是中 ...

  2. TQ210——S5PV210中断体系

    TQ210--S5PV210中断体系 中断是指 CPU 在执行程序的过程中,遇到异常情况需要处理, CPU停 止当前程序的运行,保存当前程序运行处的必要参数,转去处理这些异常情况, 处理结束后再返回当 ...

  3. ARM 中断--IRQ and FIQ配置--外部配置

    ARM 中断--IRQ and FIQ配置--外部配置 中断分为外部中断和定时器中断: 中断源都是有一个触发条件,条件满足就会产生中断.不同的中断源触发条件不一样 ARM中中断分为两种:FIQ(fas ...

  4. x86架构中断基础介绍

    BIOS/UEFI基础--x86架构中断基础介绍 说明 本文讲的是Intel的x86架构下的中断. 参考的文档主要是<64-ia-32-architectures-software-develo ...

  5. JSTL 及 tablibs 的简单介绍和配置方法

    JSTL 及 tablibs 的简单介绍和配置方法 jstl 简介 jstl 的全称就是jsp standard tag libraries, 就是jsp里的标准标签库. 引用jstl技术能在jsp种 ...

  6. 03_MyBatis基本查询,mapper文件的定义,测试代码的编写,resultMap配置返回值,sql片段配置,select标签标签中的内容介绍,配置使用二级缓存,使用别名的数据类型,条件查询ma

     1 PersonTestMapper.xml中的内容如下: <?xmlversion="1.0"encoding="UTF-8"?> < ...

  7. Redis数据库(一)——介绍、配置与优化

    Redis数据库(一)--介绍.配置与优化 一.关系数据库与非关系型数据库 1.关系数据库 2.非关系型数据库 3.关系数据库与非关系型数据库区别(三个方向) 数据存储方式不同 扩展方式不同 对事务性 ...

  8. CCNA课堂练习:OSPF的介绍及配置

      CCNA浅谈OSPF的配置 今天我们来谈谈路由器OSPF的配置,那我先来介绍一下OSPF的特点: 1.对网络发生的变化能够快速响应 2.当网络发生变化的时候发送触发式更新 •3.支持VLAN 4. ...

  9. SpringCloud Sentinel 熔断降级、热点参数限流、与系统自适应限流介绍与配置

    一.熔断降级介绍与配置 概述:除了上一章节讲解的sentinel的流量控制之外,sentinel还提供了熔断降级功能.与处理高并发的系统自我保护机制不同的是,熔断降级主要防止当前接口不可用时,导致依赖 ...

最新文章

  1. Python源码学习:内建类型简析并简析int对象
  2. 2017ACM暑期多校联合训练 - Team 7 1009 HDU 6128 Inverse of sum (数学计算)
  3. Python-基于flask的接口框架
  4. 国内 GitHub 造假黑色产业链曝光;开源开发者撤销对 ICE 禁用的决定
  5. Java历经20年沧桑,将持续革新
  6. 谷歌 Chrome Dev Tools 浅析 – 成为更高效的 Developer
  7. 通用模块 -- Dubbo 用户模块
  8. 【SpringBoot】项目打成 jar 包后关于配置文件的外部化配置
  9. 腾讯广告算法大赛 | 第三周周冠军心得分享
  10. perl的几个小tips
  11. 【前端 · 面试 】HTTP 总结(十一)—— HTTPS 概述
  12. Android Studio实现前后台分离的选课系统
  13. 网络爬虫研发重点介绍
  14. 使用Sharepoint Services 3.0构建基本网站
  15. LM393 电压比较器及其典型电路介绍
  16. linux火狐插件目录,Firefox的插件目录在哪里?
  17. BPMN,BPEL,XPDL
  18. 首次试水天池数据大赛——7个小时玩了把美年健康AI大赛
  19. 申宝证券-题材股活跃沪指尾盘收红
  20. 安卓开发入门教程!终于有人把安卓程序员必学知识点全整理出来了,附答案

热门文章

  1. 牛客网 D-图图(广搜)
  2. Go Ticker实现原理剖析(轻松掌握Ticker实现原理)
  3. UnicodeEncodeError: 'gbk' codec can't encode character '\uXXX' in position
  4. 对抗网络之PG-GAN,无条件下生成更真实的人脸图像
  5. Gif动态图片怎样在线生成?一招快速完成gif在线制作
  6. 201809-3-元素选择器
  7. 浏览器怎么录制网页视频?3种网页视频录制方法
  8. JDK19都出来了~是时候梳理清楚JDK的各个版本的特性了【JDK16特性讲解】
  9. carte执行job任务时出现中文乱码
  10. 天翼4gdongle linux,SIM7600X 4G DONGLE用户手册 (重定向自SIM7600CE-CNSE 4G DONGLE)