中断:
中断是内核的外部发生某一事件,产生触发信号,引起处理器暂停当前执行的程序,转去执行处理相应事件的程序,执行完毕后返回。
中断是CPU和外部设备交换数据的主要方式之一,是用户要求计算机为自己服务的主要方式之一,针对不同的CPU,具体的做法是不一样的。
异常:
异常是程序执行过程中如果发生了意外事件,例如ARM体系中的软件中断、未定义指令、调试事件及系统复位功能等,正常执行的程序被暂停,转到相应的处理程序执行。
关系:
中断可看成是异常的一种。中断对内核来说是意外突发事件,请求信号来自外部;异常是内核产生的,即是在执行指令或存取中产生的。
能够导致CPU产生中断的来源就是中断源。
分类 | 举例 |
---|---|
(1)常见的外部输入输出设备 (IRQ) | 键盘,打印机,鼠标等 |
(2)数据通道中断源 (IRQ) | 软盘,硬盘等 |
(3)实时过程产生的中断 (IRQ) | 实时设备的采样中断,为某些实施控制设备发送控制信号 |
(4)定时或者计数信息 (IRQ) | 计时、计数到一定值可以发出中断申请。一般都是外部中断,也可以是内部中断,例如实时时钟。 |
(5)故障源 | 一般是不可屏蔽中断(NMI)或者系统异常 |
(a)外设故障: 电源掉电,运行超限、监控诊断程序产生的诊断错误等。 | |
(b)计算机故障:处理器出错(运算溢出、除数为0、非法数据格式),内存出错(非法地址、主存储器页面失效、数据或地址校验错),控制器出错(非法指令、未定义的操作码、堆栈溢出)等。 | |
(6)程序调试设置的中断源 | 硬件断点:硬件调试器,软件断点:调试程序应支持单步运行和断点运行 |
不同的中断源又可以分为条件中断和无条件中断。
控制CPU处于开中断或者关中断的状态,也是和CPU有关。Cortex-M处理器内核中有中断屏蔽寄存器PRIMASK、FAULTMASK和BASEPRI,用于异常或者中断的屏蔽管理。有时CPU根据自己的工作状态会切换系统的开关中断状态。
对于用户和开发人员,需要根据重要程度确定和处理实际中断源的优先级。更高优先级的异常具有更小的优先级编号。一些异常,比如复位(-3)、不可屏蔽中断NMI(-2)和硬件错误HardFault(-1)具有固定的优先级(优先级 ≠ \not= =异常编号)。除此之外,鱼油优先级编号0-255内的其他异常和中断具有可编程的优先级。 (中断源的优先级默认确定,部分优先级特别是外部优先级可以编程修改。)
调用异常服务程序必须将处理器的指令指针转移到异常服务程序的入口,方法是使用中断向量表。
中断向量表是系统RAM或者系统ROM的一个区域 ,向量表的大小取决于CPU支持的中断类型和数量。 有两种类型:
经典的ARM7TDMI处理器采用的是指令型的中断向量表,而Cortex-M处理器采用矢量中断。
下面看看Cortex-M的矢量中断,向量表一定是在地址0开始的一段位置,只要异常编号乘以4可以得到向量表中该矢量地址的起始位置。
例如:编号为3的HardFault异常,其中断向量地址:3*4 = 0x0000000C
Cortex-M微处理器的异常分为软中断源和硬中断源。
硬中断源除了内核的系统异常(包括复位、硬件错误、存储器管理错误和总线错误等)外,主要是外部中断源,由嵌套向量中断控制器NVIC(Nested Vectored Interrupt Controller)来管理。
主要是
软中断源:
Cortex-M处理器支持的异常源通过异常类型编号来标识,都具有优先级特性,多数异常和中断的优先级还可以编程设置。异常类型编号1~15的为系统异常,类型16及以上的则为外部中断输入。(前三个也是复位、NMI、硬件错误)
ARM Cortex-M4处理器共支持240个外部中断,外部中断输入#0~#239也对应到NVIC的中断输入。
CMSIS编号是厂商决定的,会提供在头文件IRQn的typedef段中进行异常编号的枚举值和枚举定义符号,所有的系统异常都是负值。
Cortex-M处理器内核中有中断屏蔽寄存器PRIMASK、FAULTMASK和BASEPRI,用于异常或者中断的屏蔽管理。
PRIMASK寄存器
FAULTMASK寄存器
BASEPRI寄存器
NVIC中的寄存器
Cortex-M的处理器的中断优先级都是有NVIC何SCB定义的寄存器来管理的。
Cortex-M处理器例如Cortex-M3、M4芯片支持的优先级数量可选择是2的倍数,也就是8、16、32等值,其优先等级的数量由芯片厂商具体决定。数量越大的优先级会增加NVIC的复杂度,增加功耗降低速度。
优先级的减少是通过去除优先级配置寄存器的最低位LSB来实现的
例如:写出Cortex-M3/M4处理器的3位优先级宽度可实现的等级:
8位的优先级配置寄存器,设计使用3位优先级,可知第0~4位(共5位)未实现,都置0。可能的优先级就是
0x00(最高优先级)、0x20 、 0x40、0x60、0x80、0xA0、0xC0、0xE0(1110 0000)。
以此类推,若使用了4位优先级宽度就是2^4=16个可编程优先级。
Cortex-M0:
Cortex-M0+处理器的NVIC_IPR只有8个寄存器,则最多支持32个IRQ中断源(4x8=32),加上16个内核异常,一共有48个中断源。中断优先级配置PRI_xx的8位中只有最高2位[7:6]有效,则只有4个可用的优先级配置:0x00、0x40、0x80、0xC0。【这些都是厂家规定了的】
Cortex-M0+处理器的优先级配置相对简单,优先级寄存器存放的配置PRI_xx越低则中断优先级越高,优先级比较高的中断可以随时抢占优先级低的中断服务。一般默认中断源的异常编号越低,其中断优先级也越高,用户可以根据实际需要进行相应配置。
Cortex-M4:
Cortex-M4处理器的8位优先级寄存器进一步划分为两个部分:分组优先级(也称抢占优先级,pre-emption priority)和子优先级(subpriority)。
Cortex-M4处理器的系统控制块SCB中有一个优先级分组的配置寄存器SCB_AIRCR(应用中断和复位控制寄存器),其中PRIGROUP域的值决定了8种不同的优先级分组方式:
配置寄存器宽度多少是用户可以决定的;
配置了宽度x之后,就表示每个8位里只有高x位时可用的,然后在这x位里,有多少个是“抢占优先级域”,有多少个“子优先级域”,就是由分组决定的。
例:配置寄存器的宽度为3,AIRCR设置的优先级分组为5。
宽度为3,就有总共8个优先级。分组为5,即只有最高两位是抢占优先级域,第5位是子优先级域。
这样的话就有4个分组(抢占)优先级(第7~6位),分别是0x00,0x40,0x80,0xC0,
然后每个分组优先级下具有2个子优先级。
所有的子优先级为:0x00,0x20,0x040,0x60,0x80,0xA0,0xC0,0xE0。
但是要注意,如果配置寄存器的宽度是3位,但是优先级分组是1,那是什么情况?
情况就是:子优先级域的值都是0,这样就不存在子优先级的分组了,
总共优先级个数是8,即0x00,0x20,0x040,0x60,0x80,0xA0,0xC0,0xE0,
所有的子优先级也是0x00,0x20,0x040,0x60,0x80,0xA0,0xC0,0xE0。
Cortex-M处理器的向量表一般被定义在微控制器供应商的启动代码中。起始地址0x00000000处是Flash存储器或者ROM设备,运行时不能修改,但是为了运行时动态修改或者重定义向量表,Cortex-M4处理器采用了**“向量表重定位”**的方式。
“向量表重定位”方式提供一个可编程的向量表偏移寄存器 SCB_VTOR,SCB_VTOR寄存器配置新向量表的基地址。
一般是将新向量表的位置重定位为RAM存储器的首地址(0x20000000)。由于最小的中断向量表要求对齐为128字节,所以SCB_VTOR寄存器的最低7位保留且被强制置为0。
映射要求是,必须注意向量表的起始地址的要求:必须先求出系统中共有多少个向量,再把这个数字向上增大到是 2 的整次幂,而起始地址必须对齐到后者的边界上。因此中断向量表的大小一般要被扩展为下一个2的整数次方。
例1:Cortex-M微控制器有32个或者75个中断源的情况下,请给出向量表的大小以及可能设置的向量表的基地址。
32个中断源的向量表大小为:
(32(用于中断)+16(系统异常))×4(每个向量的字节数)=192
扩展为下一个2的整数次方得到256字节(一个地址是4个字节,),因此向量表的基地址可被设置为0x00000000、0x00000100、0x00000200等。
75个中断源的向量表大小为:
(75(用于中断)+16(系统异常))×4(每个向量的字节数)=364
扩展为下一个2的整数次方得到512字节,因此向量表的基地址可被设置为0x00000000、0x00000200、0x00000400等。
初始化过程
Cortex-M处理器在CPU复位后,所有中断处于禁止状态,且默认的优先级为0。在使用任何一种中断之前,需要进行如下操作:
中断申请过程
若满足下列的中断申请条件,Cortex-M处理器会接受中断申请:
Cortex-M处理器的NVIC控制器支持,不需要配置NVIC的寄存器来选择其中一种中断类型:
中断挂起状态可以通过中断设置挂起寄存器NVIC_ISPR[n]和中断清除挂起寄存器NVIC_ICPR[n]来访问。
注意:
注意以下几点:
中断响应过程
Cortex-M处理器在中断响应过程中,系统自动完成以下的操作:
中断服务过程
执行中断处理服务程序时,处理器处于处理模式,处于特权访问等级,使用主栈指针MSP。
中断嵌套是正在执行的处理会被挂起(pending)而被更高优先级的中断抢占。
中断处理服务结尾,程序代码执行的返回会引起EXC_RETURN数值被加载到程序计数器PC中,触发中断返回过程。
**每个外部中断都有一个活跃状态位,当中断处理开始执行时该位会被置1,中断返回后会被清零。**活跃状态位保存在中断状态寄存器NVIC->IABR中。可能有多个被置位的活跃状态位。
中断返回
异常返回是由一个特殊的值EXC_RETURN来触发。该数值由异常返回指令写入PC时,就会触发异常返回过程。
BX LR 若EXC_RETURN数值仍在LR中,则在异常处理结束时可以使用BX LR指令执行中断返回。
POP {PC} 或 POP {……,PC} 异常处理后,LR的值通常会被压入栈中
加载(LDR)或多寄存器加载(LDM) 加载指令以PC为目的寄存器可以产生中断返回。