【裸机开发】中断系统 —— 中断向量表(设置中断向量偏移的原因)

news/2024/11/23 22:11:49/

之前的LED驱动不存在中断,也就不包含中断的初始化。如果程序包含了中断,我们应还需要初始化哪些内容?要解决这个问题,我们需要先了解一个中断系统包含了哪些内容。

中断向量表描述中断对应的中断服务函数,保存在程序开始运行的地方,默认是0x00000000

中断控制器(NVIC、GIC)中断系统的管理机构

中断使能:某个外设的中断使能(要使用某个外设的中断,要先使能这个外设的中断)

中断服务函数:当中断产生时,中断服务函数就会被调用(中断处理逻辑都在中断服务函数中)


目录

一、中断向量表

1、什么是中断向量表?

2、中断类型

二、为什么要设置中断向量表偏移 

1、原因分析

2、如何确定偏移量

3、如何设置

三、汇编编写中断向量表框架


一、中断向量表

1、什么是中断向量表?

中断向量表的作用是描述中断对应的中断服务函数。保存在程序开始运行的地方,默认是0x00000000,可以通过设置中断向量偏移,来改变中断向量表的位置。

Cortex-M 的中断向量表中列举出了所有的中断,每一个中断对应一个中断服务函数;而 Cortex-A 的中断向量表则是将中断分为了 7 类

  • 某个中断发生时,先判断属于哪一类
  • 然后,去中断向量表找对应类的中断服务函数
  • 随后,执行对应的中断服务函数
  • 最后,回到程序暂停的下一个位置

中断向量表所写的就是不同中断类型所对应的中断服务函数地址

2、中断类型

中断大致可以分为七种类型,不同的中断类型对应着一种 CPU 工作模式,当中断产生时,CPU 会先切换到对应的模式,然后再处理中断。其中我们最常用的是 Reset IRQ 中断。

  • ResetCPU 复位以后就会进入复位中断,我们可以在复位中断服务函数里面做一些初始化工作,比如初始化 SP 指针、DDR 等
  • Undefined Instruction:如果指令不能识别的话就会产生此中断
  • SWI:Linux 的系统调用会用 SWI 指令来引起软中断,通过软中断来陷入到内核空间
  • Prefetch Abort:预取指令的出错的时候会产生此中断
  • Data Abort:访问数据出错的时候会产生此中断
  • IRQ外设中断都会引起此中断的发生
  • FIQ:快速中断,如果需要快速处理中断的话就可以使用此中断
偏移地址中断类型中断模式
0x00复位中断(Reset)SVC
0x04未定义指令中断(Undefined Instruction)Undef
0x08软中断(Software Interrupt,SWI)SVC
0x0C指令预取中止中断(Prefetch Abort)Abort
0x10数据访问中止中断(Data Abort)Abort
0x14保留(Reserved)-
0x18IRQ 中断(IRQ Interrupt)IRQ
0x1CFIQ 中断(FIQ Interrupt)FIQ

注意:因为中断向量表是放在程序运行的起始位置,所以这里的偏移位置是相对于起始位置而言的

二、为什么要设置中断向量表偏移 

1、原因分析

中断向量表保存在程序运行的起始位置,默认是 0x00000000。根据参考手册中的内存映射表我们发现, 0x00000000 的位置保存了 boot rom,也就是设备上电启动的相关内容,为了不占用其他部分的内容,我们决定对中断向量表施加一个偏移。

中断控制器(GIC)可以配置中断向量表的偏移位置。裸机开发的环境下,我一般在Reset 中断服务函数中手动指定中断向量表的位置;在有 OS 的环境下,OS 会初始化中断控制器,并将中断向量表放置在一个没有被保留的地址空间中。

2、如何确定偏移量

考虑到 RAM 和 DDR 的范围,我们一般将程序保存在 DDR 中。

  • RAM:CPU内部的一段可用内存,imx6ull内部RAM的大小为128K(0X900000~0X91FFFF)
  • DDR:CPU外的存储器,封装在SOC 中,DDR的大小为 256M 或者 512M(虽然看着有2048,但是受到总线约束,CPU可访问的大小是256M)

DDR 的范围较广,考虑到后续的系统移植,所以使用的是DDR。假设中断向量表设为 0x83000000,其实就是在告诉CPU,中断发生时,到 0x83000000 的位置去找对应的中断服务函数。

其实我们也可以将中断向量表和存储地址都设置成 0x87800000

3、如何设置

通过汇编设置

如果是汇编形式,建议放在 Reset 中断服务函数中,因为设备上电就会触发 Reset 中断,然后去执行 Reset 中断服务函数。

/* 复位中断服务函数 */ 
Reset_Handler:/* ... */ldr r0, =0x87800000         /* 设置中断向量表的偏移 */dsbisbmcr p15, 0, r0, c12, c0, 0dsbisb/* ... */

调用 C 函数

我们可以直接调用 C 函数来设置中断向量表,只要在中断发生之前设置即可。一般放在中断初始化的函数中。

/* 设置中断向量表偏移 */
__set_VBAR((uint32_t)0x87800000);

三、汇编编写中断向量表框架

1、局部流程

中断向量表保存在程序运行的起始位置,默认是 0x00000000。其实就是在告诉内核,每一个中断对应的中断服务函数位置在哪。假设我们要设置 Reset 中断的服务函数地址。

.global _start_start:/* 把 Reset_Handler 的地址保存到 pc 指向的位置 */ ldr pc, =Reset_Handler          /* 复位中断服务函数 */ 
Reset_Handler:b Reset_Handler      @ 暂时先死循环,后面再修改              

pc 是程序计数器,用于保存下一次要执行的指令地址。默认情况下,程序从 0x00000000 开始执行,即 pc 最开始拿到的地址就是 0x00000000,这里其实就把 Reset_Handler 的地址保存到了 0x00000000 的位置。

随后,pc 会指向下一个地址,即 0x00000004。

2、整体框架

其他中断也是类似的,我们借助pc寄存器的地址自动递增的特性,逐个设置各个中断服务函数的地址。至于具体实现,这里有 Reset 中断 和 IRQ 中断的汇编部分。

Reset中断:仅包含汇编部分,因为一般只有在复位或者刚上电的时候才会触发,没有需要特意实现的逻辑。Reset 中断服务函数(汇编部分)

② IRQ 中断:包含汇编部分和 C代码部分。

  • 汇编部分用于初始化环境
  • C 代码部分用于逻辑实现
_start:ldr pc, =Reset_Handler          /* 复位中断 */ ldr pc, =Undefined_Handler      /* 未定义指令中断 */ldr pc, =SVC_Handler            /* SVC(Supervisor)中断*/ldr pc, =PrefAbort_Handler      /* 预取终止中断 */ldr pc, =DataAbort_Handler      /* 数据终止中断 */ldr pc, =NotUsed_Handler        /* 保留中断 */ldr pc, =IRQ_Handler            /* IRQ 中断 */ldr pc, =FIQ_Handler            /* FIQ(快速中断) *//* 复位中断 */ 
Reset_Handler:b Reset_Handler/* 未定义指令中断 */ 
Undefined_Handler:b Undefined_Handler/* SVC */ 
SVC_Handler:b SVC_Handler/* 预取终止中断 */ 
PrefAbort_Handler:b PrefAbort_Handler/* 数据终止中断 */ 
DataAbort_Handler:b DataAbort_Handler    /* 保留中断 */ 
NotUsed_Handler:b NotUsed_Handler /* IRQ 中断 */ 
IRQ_Handler:b IRQ_Handler   /* FIQ(快速中断) */ 
FIQ_Handler:b FIQ_Handler  

http://www.ppmy.cn/news/534755.html

相关文章

Matplotlib---饼图

1. 饼图 pie()函数用于绘制饼图,其基本语法如下: plt.pie(x, explodeNone, labelsNone, colorsNone, autopctNone, startangleNone, shadowFalse) 其中,参数含义如下: - x: 数组,表示饼图中每个部分的数值大小。 -…

有关STM32核心板控制松下伺服电机

有关STM32核心板控制松下伺服电机 源码下载链接:https://download.csdn.net/download/qq_43751669/12125876 硬件的使用: 首先是这次课程设计的硬件的使用,在ARM部分,老师给我们提供了普中科技的核心板以及一块普中科技的一个L…

国内电容市场份额达七成,松下如何抢占高地?

01 电容市场发展 电容器是三大电子被动元器件之一,是电子线路中不可缺少的基础元件,约占全部电子元件用量的40%,产值的66%。中国电容器行业规模增速持续高于全球规模增速,中国市场的快速增长成为拉动全球电容器行业规模增长的主要…

MCU(Cortex - M3/M4)启动加载过程和内存分配原理 笔记

最近发现对基础不太熟悉,写篇笔记记录一下MCU启动到用户C语言运行,之前做了那些工作,同时flash和Ram又分别保存了那个数据,每一段又是什么意义,方便后续自己忘记了,查阅。 一、 MCU启动 在MCU上电/复位之后…

Matplotlib---散点图

1. 散点图 scatter函数用于绘制散点图。下面是scatter函数的语法格式: scatter(x, y, sNone, cNone, markerNone, cmapNone, normNone, vminNone, vmaxNone, alphaNone, linewidthsNone, edgecolorsNone, **kwargs)参数解释: x:指定散点的…

软件项目管理 第三章软件项目的启动过程课后习题参考答案——主编:李冰、张桥珍、刘玉娥

第三章 软件项目的启动过程 课后习题参考答案 1.选择题 (1)乙方在项目初始阶段的主要任务不包含以下哪一项(D)。 A. 项目分析 B. 竞标 C. 合同签署 D. 合同管理 (2)项目章程中不…

Redis入门(2)-字符串

String是Redis最基础、最常见的类型,string类型的value中可存放任意数据,包括数值型、二进制的图片、音频、视频、序列化对象等。一个String类型的value最大是512M. 1.getset k v 若key存在返回之前的值,若不存在返回nil 2.strlen key 返…

Spark RDD | 常用函数讲解与代码实践

😄 因为spark里用的就是RDD数据结构来存储数据,所以对数据处理离不开RDD的各种函数操作咯!这一节就跟着梁云大佬打卡下如何处理RDD。【下面章节有🔥的是用的比较多的函数】 文章目录 0、初始化pyspark环境与driver介绍0.1、初始化0.2、driver是啥?1、创建RDD1.1、法1:通…