NVIC与中断控制
第9章-Cortex-M3异常和中断

第九章Cortex-M3异常和中断9.1Cortex-M3异常91C t M39.2NVIC与中断控制929.1.1 异常类型异常。
CM3支持为所有能打断正常执行流的事件都称为CM3支持为数众多的系统异常和外部中断。
异常是另一种形式的中断,它是由内部fault引起的,或者内核的SysTick、SVCall等。
而中断是由随机的外部事件引发的。
件引发的编号为1~15的对应系统异常;编号为16~255的对应外部中断。
除了个别异常的优先级被定死外,其它异常的优先级都是可编程的。
可编程的当前运行的异常编号,是由特殊寄存器IPSR或NVIC的中断控制状态寄存器来给出的。
断控制状态寄存器来给出的异常表异常号异常类型优先级描述0N/A N/A没有异常在运行1复位-3 (最高)复位2NMI-2 不可屏蔽中断(外部NMI 输入)3硬件fault-1各种fault情况4内存管理fault可编程内存管理fault;MPU 访问非法地址5总线fault可编程总线fault,比如预取终止6用法fault可编程由于程序fault或尝试访问协处理器导致的异常7-10保留N/A—11SVCall可编程系统服务调用12调试监视器可编程调试监视器(续)13保留N/A—14PendSV可编程可挂起系统设备申请15SysTick可编程系统时钟定时器16外部中断#0可编程外部中断17外部中断#1可编程外部中断…………255外部中断#239可编程外部中断当一个被使能的异常发生时,如果它不能够被立即执行,它将被挂起(pending)。
9.1.2 优先级定义在CM3中优先级对于异常来说很关键的它决定一个 在CM3中,优先级对于异常来说很关键的,它决定个异常是否能被屏蔽,以及在未被屏蔽的情况下何时可以响应。
应优先级的数值越小,则优先级越高。
CM3支持中断嵌套,使得高优先级异常会抢占(preempt)低优先级异常。
3个系统异常:复位、NMI以及硬fault有固定的优先级,并且它们的优先级号是负数,从而高于所有其它异常。
nvic嵌套向量中断控制器工作原理

一、引言Nvic嵌套向量中断控制器(Nested Vectored Interrupt Controller)是一种常见的中断控制器,它在嵌入式系统中扮演着重要的角色。
本文将介绍Nvic的工作原理,帮助读者更好地理解这一关键的硬件组件。
二、Nvic的基本概念Nvic是一种硬件组件,用于管理和分发系统中的中断请求。
在嵌入式系统中,当发生外部事件或者特定的处理器状态发生变化时,需要立即中断当前的程序执行,执行特定的中断服务程序。
而Nvic就是用来协调这些中断请求的,确保它们按照优先级和顺序得到正确的处理。
三、中断控制器的作用1.管理中断请求中断是在嵌入式系统中的一种重要的事件响应机制。
当外部设备(如传感器、通信接口等)产生需要处理的事件时,会向处理器发送中断请求。
而中断控制器就是负责接收、管理和分发这些中断请求的硬件组件。
2.中断优先级在一个嵌入式系统中,可能同时出现多个中断请求,此时中断控制器需要根据中断请求的优先级决定哪个中断将被优先处理。
Nvic通过优先级编码的方式,能够准确地确定中断的优先级,确保高优先级的中断能够得到及时处理。
四、Nvic的工作原理1.中断向量表Nvic通过中断向量表来实现对中断请求的管理。
中断向量表是一张表格,每个中断都有一个特定的中断向量号。
当中断控制器接收到中断请求时,根据中断向量号可以迅速定位到对应的中断服务程序的入口位置区域,从而进行中断处理。
2.中断优先级编码Nvic使用中断优先级编码的方式来确定中断的优先级。
在Nvic中,中断请求会按照其具体的中断向量号进行编码,从而确定其优先级。
当多个中断请求同时到达时,Nvic会根据优先级编码来决定哪个中断会被优先处理。
3.嵌套中断Nvic支持嵌套中断的机制,即在一个中断服务程序的执行过程中,如果遇到了更高优先级的中断请求,Nvic可以暂停当前中断服务程序的执行,转而处理更高优先级的中断请求。
这种机制可以确保高优先级的中断能够得到及时处理,提高系统的响应速度。
nvic_init函数解读 -回复

nvic_init函数解读-回复NVIC_Init函数是STM32中断控制器初始化函数。
本文将逐步解读NVIC_Init函数的具体内容,并对其作用和使用进行讲解。
1. 函数原型:void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);函数原型告诉我们NVIC_Init函数接受一个指向NVIC_InitTypeDef 结构体的指针作为参数,并且没有返回值。
2. 函数作用:NVIC_Init函数用于初始化STM32的中断控制器配置。
3. 参数解析:参数NVIC_InitStruct是一个NVIC_InitTypeDef类型的指针,用于配置中断控制器。
4. NVIC_InitTypeDef结构体:NVIC_Init函数通过NVIC_InitTypeDef结构体来配置中断控制器。
该结构体定义如下:typedef struct {uint8_t NVIC_IRQChannel; 中断通道号,范围从0到239uint8_t NVIC_IRQChannelCmd; 中断通道使能(开启/关闭)命令uint32_t NVIC_IRQChannelPreemptionPriority; 中断通道抢占优先级uint32_t NVIC_IRQChannelSubPriority; 中断通道子优先级FunctionalState NVIC_IRQChannelCmd; 中断通道命令使能(开启/关闭)} NVIC_InitTypeDef;中断通道号(NVIC_IRQChannel)用于指定要配置的中断通道,其取值范围从0到239不等,具体的中断号可以在芯片手册中找到。
中断通道使能命令(NVIC_IRQChannelCmd)用于控制中断通道的使能状态,可以选择开启或关闭。
中断通道抢占优先级(NVIC_IRQChannelPreemptionPriority)用于设置中断通道的抢占优先级。
nvic中断控制原理

nvic中断控制原理
NVIC,全称为嵌套向量中断控制器,是ARMCortex-M微控制器中的核心组件之一。
它的工作原理如下:
1.中断优先级:每个中断都有一个固定的优先级。
优先级高的中断在发生时可以立即打断正在执行的指令序列。
ARMCortex-M微控制器支持动态优先级,可以在运行时改变中断的优先级。
2.中断向量表:NVIC使用一个特殊的存储区域来保存中断向量表(InterruptVectorTable)。
中断向量表是一个数组,其中每个元素都是一个指向中断处理程序的地址。
当中断发生时,NVIC将比较新中断与当前中断的优先级,如果新中断优先级高,则立即处理新中断。
3.中断屏蔽:NVIC具有可编程的中断屏蔽寄存器,用于控制哪些中断被允许或禁止。
通过设置这些寄存器的值,可以控制哪些中断信号可以触发中断事件。
4.自动保存和恢复处理器状态:在ISR(中断服务程序)结束时,NVIC将从栈中恢复相关寄存器的值,进行正常操作,因此花费少量且确定的时间处理中断请求。
总之,NVIC通过优先级管理、向量表、屏蔽寄存器和自动保存恢复处理器状态等功能,实现了对微控制器中断的全面控制和管理。
arm nvic_setpendingirq 用例

arm nvic_setpendingirq 用例ARM NVIC_SetPendingIRQ用例ARM嵌入式处理器是当前应用广泛的一种处理器架构,在许多嵌入式系统中被使用。
在这些系统中,中断是一种常见的机制,用于实现处理器与外部设备的异步通信。
ARM处理器提供了一组用于管理中断的功能,其中之一是NVIC_SetPendingIRQ函数。
NVIC_SetPendingIRQ函数用于设置中断请求(IRQ)线上的待决中断。
当对应IRQ线上的待决中断被设置后,一旦中断使能,该中断将被激活,并且处理器将跳转到中断服务程序。
下面是一个关于如何使用NVIC_SetPendingIRQ的示例。
首先,我们需要在程序中包含头文件和定义相关变量。
#include <stdint.h>#include <stm32f4xx.h>// 定义待决中断的IRQ号#define MY_INTERRUPT_IRQ_NUMBER EXTI0_IRQn然后,我们需要定义中断服务程序(ISR),用于处理中断发生时的操作。
void EXTI0_IRQHandler(void){// 在这里添加中断服务程序的操作// 例如,对外设进行读写、数据处理等}接下来,我们需要在main函数中进行初始化设置。
int main(){// 初始化系统时钟等相关设置// 配置GPIO外部中断GPIO_InitTypeDef GPIO_InitStruct;EXTI_InitTypeDef EXTI_InitStruct;NVIC_InitTypeDef NVIC_InitStruct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStruct);SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0); EXTI_InitStruct.EXTI_Line = EXTI_Line0;EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;EXTI_InitStruct.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStruct);NVIC_InitStruct.NVIC_IRQChannel = MY_INTERRUPT_IRQ_NUMBER;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x00;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);while(1){// 在这里添加主程序处理逻辑// 检测是否发生中断请求,并设置待决中断if(some_condition_is_met){NVIC_SetPendingIRQ(MY_INTERRUPT_IRQ_NUMBER);}}}在上述示例中,首先通过RCC_APB2PeriphClockCmd和RCC_AHB1PeriphClockCmd函数启用相关外设的时钟。
nvic中断控制原理 -回复

nvic中断控制原理-回复NVIC(Nested Vectored Interrupt Controller)中断控制器是一种硬件模块,用于管理微处理器上的中断信号。
在嵌入式系统中,中断是处理器根据外部事件或内部条件而自动触发的一种机制。
NVIC中断控制器的作用是将多个中断源连接到处理器,并根据中断的优先级和状态来控制中断的触发和处理顺序。
下面,我们将深入探讨NVIC中断控制器的工作原理,包括中断优先级、中断向量表和中断处理过程。
一. 中断优先级NVIC中断控制器可以管理多个中断源,每个中断源都有一个特定的优先级。
中断优先级决定了中断处理的顺序,优先级较高的中断将在优先级较低的中断之前处理。
1. 优先级分组中断优先级分组是指将中断源分成若干组,每个组都有自己的优先级范围。
优先级分组可以根据系统需求进行配置,常见的分组方式包括4位抢占优先级和4位响应优先级、3位抢占优先级和1位响应优先级等。
2. 中断优先级设置对于每个中断源,可以设置其优先级。
一般来说,数值较小的中断具有更高的优先级。
在NVIC中断控制器中,中断优先级由8位寄存器控制,例如NVIC_IPR[x],其中x表示中断源的编号。
通过设置寄存器的值,可以为每个中断源设置相应的优先级。
二. 中断向量表中断向量表是存储中断服务程序入口地址的表格,用于快速定位和处理中断。
在ARM Cortex-M系列处理器中,中断向量表是一个存储在内存中的固定地址。
当发生中断时,处理器会根据中断号从中断向量表中获取相应的中断服务程序入口地址。
1. 中断向量表的结构中断向量表通常由一系列指令地址组成,每个中断对应一个指令地址。
在ARM Cortex-M系列处理器中,中断向量表的起始地址存储在向量表偏移寄存器(VTOR)中,处理器会根据该地址偏移获取实际的中断服务程序入口地址。
2. 中断服务程序中断服务程序是为每个中断源编写的处理程序,用于处理中断事件。
每个中断源可能有一个或多个相关的中断服务程序。
STMNVIC中断向量表设置以及ETI中断寄存器设置
STMNVIC中断向量表设置以及ETI中断寄存器设置NVIC中断向量表设置以及EXTI中断寄存器设置⼀、开始中断的步骤A.端⼝设置。
这⾥包括了输⼊引脚的设置,务必记得打开GPIO的时钟和AFIO的时钟信号B.中断寄存器的设置C.NVIC中断向量寄存器的设置。
这⾥关键点有优先级分组设置以及中断⼊⼝地址的设置D.中断函数的书写⼆、具体设置1、端⼝设置void GPIOA_init(void){GPIO_DeInit(GPIOA);RCC->APB2ENR |= 0X00000005;GPIOA->CRL &= 0XFFFFFF00;GPIOA->CRL |= 0x00000038;GPIOA->ODR = 0X00000000;GPIOA->ODR |= 0X00000001;AFIO->EXTICR[0] |= 0X00;}a.在对端⼝进⾏任何操作之前,必须打开对应的时钟信号,其设置才能⽣效。
这⾥使⽤了GPIOA.00端⼝作为中断0输⼊,作为输⼊时⼀般我们设置为上拉输⼊,如果要设置成浮空输⼊的话,外部⼀定要加上拉电阻,这样对于过滤输⼊波动很有益处(假设在电压在3.3-2.0之间进⾏波动,时间上没尝试按键操作,因为⼀旦有按键,就应该为0,那么接了上拉的话,除⾮产⽣了低电平,否则⼩波动都会被拉⾼过滤掉)b.复⽤端⼝时钟信号的开启这⾥需要特别注意的是因为我们要对复⽤端⼝寄存器进⾏操作,所以必须打开复⽤端⼝寄存器时钟c.AFIO->EXTICR[0] |= 0X00 ,EXTICR(External interrupt configuration register)即外部中断配置寄存器。
因为所有的外部中断输⼊来源都是经由GPIO⼝输⼊的,所以我们需要选择哪⼀个中断是经由那个IO⼝输⼊的。
我所写的这条代码的意思是EXTI0的中断来源为GPIOX_0⼝输⼊。
图1从寄存器配置中我们可以看到每个中断由四位配置,那么STM32总计有16个外部中断(具体参照STM32参考⼿册P133页),因此EXTIR有四组,在书写时要注意。
微处理器9CortexM3异常(中断)处理
Cortex-M3的异常(中断)处理
优先级分组
为了对具有大量中断的系统加强优先级控制,NVIC
支持优先级分组机制。您可以使用应用中断和复位控制寄 存器中的PRIGROUP区来将每个PRI_N中的值分为占先优
先级区和次优先级区。我们将占先优先级称为组优先级。 如果有多个挂起异常共用相同的组优先级,则需使用次优 先级区来决定同组中的异常的优先级,这就是同组内的次 优先级。组优先级和次优先级的结合就是通常所说的优先 级。如果两个挂起异常具有相同的组优先级,则挂起异常 的编号越低优先级越高。这与优先级机制是一致的。
Cortex-M3的异常(中断)处理
优先级分组
中断优先级区(PRI_N[7:0])
占先区
次优先区
PRI_N 7 6 5 4 3 2 1 0
注意: 修改PRIGROUP区的值可改变占先区和 次优先区的位数。
1. 占先优先级又称 为组优先级
2. 如果两个挂起异 常具有相同的组 优先级,则挂起 异常的编号越低 优先级越高。
Cortex-M3的异常(中断)处理
优先级分组
PRIGROU P[2:0]
二进制点 的位置
中断优先级区,PRI_N[7:0]
占先区 次优先 占先优先级
级区
的数目
次优先级 的数目
b000
bxxxxxxx.y [7:1] [0]
128
2
b001
bxxxxxx.yy [7:2] [1:0] 64
4
b010
Cortex-M3的异常(中断)处理
返回
异常基于优先级的动作
在没有挂起异常或没有比被压栈的ISR优先级更高 的挂起异常时,处理器执行出栈操作,并返回到被压 栈的ISR或线程模式。
NVIC配置说明及例子代码汉化注释
STM32中Cortex-M3寄存器说明-NVIC寄存器组、系统控制SCB寄存器组、嘀嗒定时... 在STM32中用到了Cortex-M3定义的三组寄存器,有关这三组寄存器的说明不在STM32的技术手册中,需要参考ARM公司发布的Cortex-M3 Technical Reference Manual (r2p0)。
在STM32的固件库中定义了三个结构体与这三个寄存器组相对应,这三个结构体与ARM 手册中寄存器的对应关系如下:一、NVIC寄存器组STM32的固件库中有如下定义:typedef struct{vu32 ISER[2];u32 RESERVED0[30];vu32 ICER[2];u32 RSERVED1[30];vu32 ISPR[2];u32 RESERVED2[30];vu32 ICPR[2];u32 RESERVED3[30];vu32 IABR[2];u32 RESERVED4[62];vu32 IPR[11];} NVIC_TypeDef;它们对应ARM手册中的名称为ISER = Interrupt Set-Enable RegistersICER = Interrupt Clear-Enable RegistersISPR = Interrupt Set-Pending RegisterICPR = Interrupt Clear-Pending RegisterIABR = Active Bit RegisterIPR = Interrupt Priority Registers每个寄存器有240位,以Interrupt Set-Enable Registers说明,ISER[0]对应中断源0~31,ISER[1]对应中断源32~63,STM32只有60个中断源,所以没有ISER[2:7]。
参考STM32技术参考手册中的中断向量表,中断源的位置为:位置0 - WWDG = Window Watchdog interrupt位置1 - PVD = PVD through EXTI Line detection interrupt位置2 - TAMPER = Tamper interrupt......位置58 - DMA2_Channel3 = DMA2 Channel3 global interrupt位置59 - DMA2_Channel4_5 = DMA2 Channel4 and DMA2 Channel5 global interrupts二、系统控制寄存器组STM32的固件库中有如下定义:typedef struct{vuc32 CPUID;vu32 ICSR;vu32 VTOR;vu32 AIRCR;vu32 SCR;vu32 CCR;vu32 SHPR[3];vu32 SHCSR;vu32 CFSR;vu32 HFSR;vu32 DFSR;vu32 MMFAR;vu32 BFAR;vu32 AFSR;} SCB_TypeDef; /* System Control Block Structure */它们对应ARM手册中的名称为CPUID = CPUID Base RegisterICSR = Interrupt Control State RegisterVTOR = Vector Table Offset RegisterAIRCR = Application Interrupt/Reset Control RegisterSCR = System Control RegisterCCR = Configuration Control RegisterSHPR = System Handlers Priority RegisterSHCSR = System Handler Control and State RegisterCFSR = Configurable Fault Status RegistersHFSR = Hard Fault Status RegisterDFSR = Debug Fault Status RegisterMMFAR = Mem Manage Address RegisterBFAR = Bus Fault Address RegisterAFSR = Auxiliary Fault Status Register三、系统时钟寄存器组STM32的固件库中有如下定义:typedef struct{vu32 CTRL;vu32 LOAD;vu32 VAL;vuc32 CALIB;} SysTick_TypeDef;它们对应ARM手册中的名称为CTRL = SysTick Control and Status RegisterLOAD = SysTick Reload Value RegisterVAL = SysTick Current Value RegisterCALIB = SysTick Calibration Value Register---------------------------------------------------------------------------------------------------------------------- SYSTICK我不得不说意法半导体确实有点风骚!甚至有点变态。
NVIC中断优先级管理
-STM32F42xx/STM32F43xx则总共有96个中断
STM32F40xx/STM32F41xx的92个中断里面,包括10个内核中 断和82个可屏蔽中断,具有16级可编程的中断优先级,而我们 常用的就是这82个可屏蔽中断。
电子实验中心
分组配置是在寄存器SCB->AIRCR中配置:
组
AIRCR[10:8]
0
111
1
110
2
101
3
100
4
011
IP bit[7:4]分配情况 0:4 1:3 2:2 3:1 4:0
分配结果 0位抢占优先级,4位响应优先级 1位抢占优先级,3位响应优先级 2位抢占优先级,2位响应优先级 3位抢占优先级,1位响应优先级 4位抢占优先级,0位响应优先级
配置方法跟ISER一样。
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
电子实验中心
中断优先级设置
中断挂起控制寄存器组:ISPR[8]
作用:用来挂起中断
中断解挂控制寄存器组:ICPR[8]
作用:用来解挂中断
static __INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn); static __INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn);
如果两个中断的抢占优先级和响应优先级都是一样的 话,则看哪个中断先发生就先执行;
电子实验中心
NVIC中断优✓先1级. N分V组IC中断优先级分组
举例:
假定设置中断优先级组为2,然后设置 中断3(RTC中断)的抢占优先级为2,响应优先级为1。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
示例汇编代码如下: LDR R0, =0xE000ED0C ; 应用程序中断及复位控制寄存器 LDR R1, =0x05FA0500 ; 使用优先级组5 (2/6) STR R1, [R0] ; 设置优先级组 。。。。。 MOV R4, #8 ; ROM 中的向量表 LDR R5, =(NEW_VECT_TABLE+8) LDMIA R4!, {R0-R1} ; 读取NMI 和硬fault 的向量 STMIA R5!, {R0-R1} ; 拷贝它们的向量到新表中 ... LDR R0, =0xE000ED08 ; 向量表偏移量寄存器的地址 LDR R1, =NEW_VECT_TABLE STR R1, [R0] ; 把向量表重定位
... LDR R0, =IRQ7_Handler ; 取得IRQ #7 服务例程的入口地址 LDR R1, =0xE000ED08 ; 向量表偏移量寄存器的地址 LDR R1, [R1] ADD R1, R1,#(4*(7+16)) ; 计算IRQ #7 服务例程的入口地址 STR R0, [R1] ; 在向量表中写入IRQ #7 服务例程的入口地址 ... LDR R0, =0xE000E400 ; 外部中断优先级寄存器阵列的基地址 MOV R1, #0xC0 STRB R1, [R0,#7] ; 把IRQ #7 的优先级设置为0xC0 ... LDR R0, =0xE000E100 ; SETEN 寄存器的地址 MOV R1, #(1<<7) ; 置位IRQ #7 的使能位 STR R1, [R0] ; 使能IRQ #7
中断的使能与除能
中断的使能与除能分别使用各自的寄存器来控制——这与传统的,使用单
一比特的两个状态来表达使能与除能是不同的。CM3 中可以有240 对使能位/ 除能位,每个中断拥有一对。这240 个对子分布在8 对32 位寄存器中(最后一 对没有用完)。欲使能一个中断,你需要写1 到对应SETENA 的位中;欲除能 一个中断,你需要写1 到对应的CLRENA 位中;如果往它们中写0,不会有任 何效果。通过这种方式,使能/除能中断时只需把“当事位”写成1,其它的 位可以全部为零。再也不用像以前那样,害怕有些位被写入0 而破坏其对应的 中断设置(写0 没有效果),从而实现每个中断都可以自顾地设置,而互不侵 犯——只需单一的写指令,不再需要读‐改‐写。
NVIC与中断控制
• • • • • • • NVIC 概览 中断配置基础 中断使能与除能 中断的悬起与解悬 中断建立全过程的演示 软件中断 再论 SysTick 定时器
NVIC 概览
正如前文已经多次提到的,向量中断控制器,简称NVIC,是
Cortex‐M3 不可分离的一部分,它与CM3 内核的逻辑紧密耦合,有一部 分甚至水乳交融在一起。NVIC 与CM3 内核同声相应,同气相求,相辅相 成,里应外合,共同完成对中断的响应。NVIC 的寄存器以存储器映射的方 式来访问,除了包含控制寄存器和中断处理的控制逻辑之外,NVIC 还包含 了MPU的控制寄存器、SysTick 定时器以及调试控制。本章中,我们将体 检NVIC 的中断处理控制逻辑。MPU 与调试控制逻辑在后续章节中讨论。
写这些寄存器时要小心,确保对活动位的修改是经过深思熟虑的,决不能粗 心修改。否则,如果某个异常的活动位被意外地清零了,其服务例程却不知晓, 仍然执行异常返回指令,那么CM3将视之为无理取闹——在异常服务例程以外做 异常返回,从而产生一个fault。
下面讲中断控制及状态寄存器ICSR。对于NMI、SysTick定时器以及PendSV, 可以通过此寄存器手工悬起它们。另外,在该寄存器中,有好多位段都用于调试目 的。在大多数情况下,它们对于应用软件都没有什么用处,只有悬起位对应用程序 常常比较有参考价值,如表8.6所示。
悬起寄存器和“解悬”寄存器也可以有8 对,其用法和用量都与前面介绍的
使能/除能寄存器完全相同,见表8.2。
优先级 每个外部中断都有一个对应的优先级寄存器,每个寄存器占用8 位,但是 允许最少只使用最高3 位。4 个相临的优先级寄存器拼成一个32 位寄存器。如 前所述,根据优先级组设置,优先级可以被分为高低两个位段,分别是抢占优 先级和亚优先级。优先级寄存器都可以按字节访问,当然也可以按半字/字来 访问。有意义的优先级寄存器数目由芯片厂商实现的中断数目决定,优先级配 置寄存器的详细信息在附录D 中给出(表D.18)
它们也能按字/半字/字节访问,但他们是只读的,如表8.4 所示。
PRIMASK 与FAULTMASK 特殊功能寄存器 PRIMASK 用于除能在NMI 和硬fault 之外的所有异常,它有效地把当前 优先级改为0(可编程优先级中的最高优先级)。该寄存器可以通过MRS 和 MSR 以下例方式访问: 1. 关中断 MOV R0, #1 MSR PRIMASK, R0 2. 开中断 MOV R0, #0 MSR PRIMASK, R0
论——BASEPRI将停止掩蔽任何中断。
例如,如果你需要掩蔽所有优先级不高于0x60的中断,则可以如下编 程: MOV R0, #0x60 MSR BASEPRI, R0 如果需要取消BASEPRI 对中断的掩蔽,则示例代码如下: MOV R0, #0 MSR BASEPRI, R0
另外,你还可以使用BASEPRI_MAX这个名字来访问BASEPRI寄存器, 它俩其实是同一个寄存器。但是当你使用这个名字时,会使用一个条件写操 作。个中原因如下:尽管它俩在硬件水平上是同一个寄存器,但是生成的机 器码不一样,从而硬件的行为也不同:使用BASEPRI时,可以任意设置新 的优先级阈值;但是使用BASEPRI_MAX时则“许进不许出”——只允许新
另外,如果优先级组设置使得中断嵌套层次可以很深,则务请确认 主堆栈空间足够用。因为异常服务程序总是使用MSP,为安全起见,主 堆栈的容量应是最大可能需求的量(嵌套最深时需要的量)。
SETENAs: xE000_E100 – 0xE000_E11C ; CLRENAs:0xE000E180 - 0xE000_E19C
中断的悬起与解悬
如果中断发生时,正在处理同级或高优先级异常,或者被掩蔽,则中 断不能立即得到响应。此时中断被悬起。中断的悬起状态可以通过“中(CLRPEND)”来读取, 还可以写它们来手工悬起中断。
如上所述,SETENA 位和CLRENA 位可以有240 对,对应的32 位寄存器
可以有8 对,因此使用数字后缀来区分这些寄存器,如SETENA0, SETENA1…SETENA7,如表8.1 所示。但是在特定的芯片中,只有该芯片实 现的中断,其对应的位才有意义。因此,如果你使用的芯片支持32 个中断, 则只有SETENA0/CLRENA0 才需要使用。SETENA/CLRENA 可以按字/半字/ 字节的方式来访问。又因为前16 个异常已经分配给系统异常,故而中断0 的 异常号是16,(回顾第7 章中的表7.2)
此外,还可以通过CPS指令快速完成上述功能: CPSID i ;关中断 CPSIE i ;开中断 FAULTMASK更绝,它把当前优先级改为‐1。这么一来,连硬fault都 被掩蔽了。使用方案与PRIMASK的相似。但要注意的是,FAULTMASK 会在异常退出时自动清零。
掩蔽寄存器虽然能一手遮天,却都动不了NMI,因为NMI是用在最危急的 情况下的。因此系统为它开出单行道,无需挂号只是不要迟到。当NMI激活时, “谁都是省略号,唯独是你不得了,第一优先谁比你重要”!试想,如果NMI
活动状态
每个外部中断都有一个活动状态位。在处理器执行了其ISR 的第一条指令 后,它的活动位就被置1,并且直到ISR 返回时才硬件清零。由于支持嵌套, 允许高优先级异常抢占某个ISR。然而,哪怕一个中断被抢占,其活动状态也 依然为1(请仔细琢磨前文讲到的“直到ISR返回时才清零)。活动状态寄存器 的定义,与前面讲的使能/除能和悬起/解悬寄存器相同,只是不再成对出现。
中断建立全过程的演示
下面给出一个简单的例子,以演示如何建立一个外部中断。
1. 当系统启动后,先设置优先级组寄存器。缺省情况下使用组0(7位抢 占优先级,1位亚优先级)。
2. 如果需要重定位向量表,先把硬fault和NMI服务例程的入口地址写到新
表项所在的地址中。 3. 配置向量表偏移量寄存器,使之指向新的向量表(如果有重定位的话) 4. 为该中断建立中断向量。因为向量表可能已经重定位了,保险起见需要 先读取向量表偏移量寄存器的值,再根据该中断在表中的位置,计算出服务例 程入口地址应写入的表项,再填写之。如果一直使用ROM中的向量表,则无 需此步骤。 5. 为该中断设置优先级。 6. 使能该中断
被连接到系统的掉电报警线上,且系统是体外循环机的电源管理器……如果因
为中断被除能就视而不见,则会使体外循环机因断电而失能,体外循环序列可 以被意外终止,病人的生命也将丢失。
BASEPRI寄存器
在更精巧的设计中,需要对中断掩蔽进行更细腻的控制——只掩蔽优先级 低于某一阈值的中断——它们的优先级在数字上大于等于某个数。那么这个数 存储在哪里?就存储在BASEPRI中。不过,如果往BASEPRI中写0,则另当别
;高于0x40 的中断
为了把掩蔽阈值降低,或者解除掩蔽,需要使用“BASEPRI”这个名字。 上例中,把设置阈值为0xf0的那条指令改用BASEPRI,则可以操作成功。
显然,在用户级下是不得更改BASEPRI寄存器的。与其它和优先级有
关的寄存器一样,系统中表达优先级的位数,也同样影响BASEPRI中有意
中断配置基础
每个外部中断都在NVIC 的下列寄存器中“挂号”: • • • • ������ ������ ������ ������ 使能与除能寄存器 悬起与“解悬”寄存器 优先级寄存器 活动状态寄存器
另外,下列寄存器也对中断处理有重大影响
• • • • ������ ������ ������ ������ 异常掩蔽寄存器(PRIMASK, FAULTMASK 以及BASEPRI) 向量表偏移量寄存器 软件触发中断寄存器 优先级分组位段