目录
一、异常的种类 (2)
二、异常的优先级 (3)
三、NVIC异常处理 (4)
1、异常的处理 (4)
2、抢占的处理 (5)
3、异常的返回 (5)
四、复位过程 (6)
五、中断和事件 (7)
(1)硬件中断选择 (8)
(2)硬件事件选择 (8)
(3)软件中断/事件选择 (8)
(4)外部中断/事件线路映射 (8)
(5)相关的功能寄存器 (9)
六、NVIC库函数 (11)
6.1函数NVIC_PriorityGroupConfig (11)
6.2函数NVIC_Init (12)
6.3函数NVIC_StructInit (13)
6.4函数NVIC_SetVectorTable (13)
6.5函数NVIC_GenerateSystemReset (14)
6.6函数NVIC_GenerateCoreReset (14)
6.7函数NVIC_SystemLPConfig (15)
其他相关函数 (15)
七、程序设计 (16)
1、滴答时钟简单使用 (16)
2、NVIC外部中断配置实验 (17)
八、设计总结 (19)
STM32 NVIC固件库分析与应用
Cortex-M3处理器和NVIC对所有优先级进行划分和处理。所有的异常处理均在Handle 模式下进行。当出现异常时,处理器的状态被自动保存到栈中;在中断服务子程序结束之后,又会自动从栈中恢复处理器的状态。获取中断向量和状态保存是同时进行的,这提高了进入中断处理的效率。Cortex-M3处理器支持尾链技术,即当发生背靠背中断时,无需保存和恢复状态,而是继续执行。Cortex-M3处理器的一下特性,提高了处理异常的效率并降低了时间的延迟。
处理器状态的自动保存和恢复;
中断向量表读取与处理器状态保存并行处理;
支持尾链技术,当处理背靠背的中断时,不需要在2个终端服务子程序之间进行入栈和出栈操作;
可动态重设优先级;
NVIC和Cortex-M3处理器和紧密耦合,可尽早处理中断,尤其是晚到的高优先级中断;
中断的数目可以配置,1~240;
为Handle和Thread模式分别提供独立的栈和访问权限等级;
可屏蔽优先级以支持临界区。
一、异常的种类
Cortex-M3处理器将复位、不可屏蔽中断、外部中断、故障都统一为异常,异常有多种类型。故障是指指令执行时由于错误的条件所导致的异常。故障可分为同步故障和一般故障,同步故障是指当指令产生错误时就同时报告错误,而异步故障则是指当指令产生错误时无法保证同时报告错误。下表列出了异常的类型、位置和优先级。位置是指中断向量在中断向量表中的位置,是相对于中断限量表开始处字的偏移。优先级的值越小,优先级越高。
二、异常的优先级
在处理器处理异常时,优先级决定了处理器何时以及如何进行异常处理。可以给中断设置软件优先级以及对其进行分组。
优先级NVIC支持通过软件设置的优先级。通过写中断优先级寄存器的PRI_N字段可以设置优先级,范围为0~255。硬件优先级随着中断号的增加而减小,优先级0为最高优先级,255为最低优先级。
通过软件设置的优先级权限高于硬件优先级。例如,如果设置IRQ[0]的优先级为1,IRQ[31]的优先级为0,则IRQ[31]的优先级比IRQ[0]的高。但通过软件设置的优先级对复位、不可屏蔽中断和硬件故障没有影响。
当多个中断具有相同的优先级时,拥有最小中断号的挂起中断优先执行。例如,IRQ[0]和IRQ[1]的优先级都为1,则IRQ[0]优先执行。
优先级分组为了更好的对大量的中断进行优先级管理和控制,NVIC支持优先级分组。通过设定应用中断和复位中断控制寄存器的PRIGROUP字段,可以将PRI_N字段分成2个部分:抢占优先级和次要优先级,如表2所列。抢占优先级可以认为是优先级分组,当多个挂起的异常具有相同的抢占优先级时,次要优先级就起作用。优先级分组和次要优先级共同作用确定了异常的优先级,当两个挂起的异常具有完全相同的优先级时,硬件位置编号低的异常优先级被激活。
表2-1 优先级分组
优先级对异常处理的影响异常的处理异常的处理与优先级有很大的关系,异常处理中与优先级相关的操作入表2-2所列
三、NVIC异常处理
1、异常的处理
当一个异常出现以后,Cortex一M3处理器由硬件通过Dbus保存处理器状态,同时通过Ibus读取向量表中的SP,更新PC和LR,执行中断服务子程序。为了应对堆栈操作阶段到来后的更高优先级异常,Cortex—M3支持迟到和抢占机制,以便对各种可能事件做出确定性的响应。
2、抢占的处理
抢占是一种对更高优先级异常的响应机制。Cortex—M3异常抢占的处理过程如图1所示。当新的更高优先级异常到来时,处理器打断当前的流程,执行更高优先级的异常操作,这样就发生了异常嵌套。迟到是处理器用来加速抢占的一种机制。如果一个具有更高优先级的异常在上一个异常执行压栈期间到达,则处理器保存状态的操作继续执行,因为被保存的状态对于两个异常都是一样的。但是,NVIC马上获取的是更高优先级的异常向量地址。这样在处理器状态保存完成后,开始执行高优先级异常的ISR。
3、异常的返回
为了应对异常返回阶段可能遇到的新的更高优先级异常,Cortex—M3支持完全基于硬件的尾链机制,简化了激活的和未决的异常之问的移动,能够在两个异常之间没有多余的状态保存和恢复指令的情况下实现back—to—back处理。
尾链发生的2个条件:异常返回时产生了新的异常;挂起的异常的优先级比所有被压栈的异常的优先级都高。尾链发生后,Cortex—M3处理过程如图3中尾链分支所示。这时,Cortex—M3处理器终止正在进行的出栈操作并跳过新异常进入时的压栈操作,同时通过Ibus立即取出挂起异常的向量。在退出前一个ISR返回操作6个周期后,开始执行尾链的ISR。
四、复位过程
Cotex-M3处理器复位时,NVIC同时复位并控制内核从复位中释放出来。复位的过程是可完全预知的,如下表
表4-1 复位的过程
向量表
在向量表的0位置处,仅需要包含4个值:
?栈顶地址;
?复位程序的入口地址;
?非屏蔽中断ISR的入口地址;
?硬故障ISR的入口地址。
当中断允许时,不管向量表放在何处,向量总是指向所有可屏蔽异常的处理。同样,如果使用SVC指令,SVCall ISR的位置也被定位。
一个完整向量表的例子:
Unsigned in stack_base[STACK_SIZE];
Void ResetISR(viod);
Void NmiISR(viod);
┆
ISR_VECTOR_TABLE vevtor_table_at_0
{stack_base+sizeof(stack_base),
RedetISR,
NmiISR,
FaultISR,,
0.//用于内存保护单元
0, //用于总线故障
0,//用于硬件故障
0,0,0,0 //保留
SVCallISR,
0, // 用于调试监控程序
0, //保留
0, //用于可挂起的服务请求
0, //用于SysTick
//以下向量用于外部中断
Timer1ISR,,
GpioInISR
GpioOoutISR,
I2Cisr
}
五、中断和事件
外部中断/事件控制器(EXTI)由19个产生事件/中断要求的边沿检测器组成。每个输入线可以独立地配合输入类型和对应的触发事件。每个输入线都可以被独立地屏蔽,由挂起寄存器保持着状态线的中断要求。
EXTI控制器的结构图如图5-1所示,其主要特性如下:
每个中断/事件都有独立的触发和屏蔽;
每个中断线都有专用的状态线;
支持多达19个中断/事件请求;
检测脉冲宽度低于APB2时钟宽度的外部信号。
图5-1 外部中断/事件控制器框图
如果要产生外部中断,那么中断线必须事先配置好并激活。配置内容包括:根据需要的边沿检测设置2个触发寄存器、在中断屏蔽寄存器的相应位写1以允许中断请求。当外部中断线出现相应的边沿信号时,将产生一个中断请求,对应的挂起位也随着置1。通过写1到挂起寄存器,可以清除该中断请求。
如果要产生事件请求,事件请求线必须事先配置好并激活。配置内容包括:根据需要的边沿检测设置2个触发寄存器、在中断屏蔽寄存器的相应位写1以允许中断请求。当事件请求线上出现相应的边沿信号时,将产生一个事件请求脉冲,对应的挂起位不置1。
也可以通过软件在中断/事件寄存器写1,来产生一个中断/事件请求。
下面具体介绍如何配置软硬中断/事件请求。
(1)硬件中断选择
通过下面的过程,可以配置19根线为中断源:
①配置19根中断线的屏蔽位(EXTI_IMR);
②配置所选中断线的触发选择位;
③配置那些控制映射到外部中断/事件控制器(EXTI)的NVIC中断通道的允许和屏蔽位,使得19根中断线中的请求可以被正确地响应。
(2)硬件事件选择
通过下面的过程,可以配置19根线为事件源:
①配置19根事件请求线的屏蔽位;
②配置事件线的触发选择位
(3)软件中断/事件选择
可以配置19根线为软件中断/事件请求线,
通过以下过程可以产生软件中断:
①配置19根中断/事件请求线的屏蔽位;
②设置软件中断请求寄存器的请求。
(4)外部中断/事件线路映射
80个通用I/O端口可以用图5-2方式映射到
16根外部中断/事件线上。
另外3种其他的外部中断/事件控制器的
连接如下:
①EXTI线16连接到PVD输出;
②EXTI线17 连接到RTC闹钟事件;
③EXTI线18连接到USB唤醒事件。
Cortex-M3可以通过外部或内部事件来唤醒
内核,利用以上19根中断/事件请求线,可以配置任何外部I/O端口、RTC闹钟和USB 唤醒事件来唤醒CPU。图5-2 通用I/O与外部中断的映射关系
(5)相关的功能寄存器
1、中断屏蔽寄存器(EXTI_IMB)
该寄存器用来设置是否屏蔽中断请求线上的中断请求,
rw rw rw 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
图5-3 EXTI_IMR寄存器
2、事件屏蔽寄存器(EXTI_EMR)
该寄存器用来设置是否屏蔽事件请求线上的中断请求,
rw rw rw 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
图5-4 EXTI_EMR寄存器
3、上升沿触发选择寄存器(EXTI_RTSR)
该寄存器用来设置是否上升沿触发中断和事件
rw rw rw 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
图5-5 EXTI_RTSR寄存器
4、下降沿触发选择寄存器(EXTI_FTSR)
该寄存器用来设置是否上升沿触发中断和事件
rw rw rw 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw
图5-6 EXTI_FTSR寄存器
5、软件中断事件寄存器(EXTI_SWIER)
该寄存器用来软件触发中断和事件
rw rw rw 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
图5-7 EXTI_SWIER寄存器
6、挂起寄存器(EXTI_PR)
该寄存器用来保存中断/事件请求线上是否有请求
rc_w1 rc_w1 rc_w1 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
rc_w1 rc_w1 rc_w1 rc_w1 rc_w1 rc_w1 rc_w1 rc_w1 rc_w1 rc_w1 rc_w1 rc_w1 rc_w1 rc_w1 rc_w1 rc_w1
图5-8 EXTI_PR寄存器
六、NVIC库函数
函数使用:
6.1函数NVIC_PriorityGroupConfig
该参数设置优先级分组位长度
下表给出了由函数NVIC_PriorityGroupConfig设置的先占优先级和从优先级可取的值
1. 选中NVIC_PriorityGroup_0,则参数NVIC_IRQChannelPreemptionPriority对中断通道的设置不产生影响。
2. 选中NVIC_PriorityGroup_4,则参数NVIC_IRQChannelSubPriority对中断通道的设置不产生影响。
NVIC_IRQChannelCmd
该参数指定了在成员NVIC_IRQChannel中定义的IRQ通道被使能还是失能。这个参数取值为ENABLE或者DISABLE。
例:
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);//抢占优先级字段为1,次要优先
级字段为3
6.2函数NVIC_Init
NVIC_InitTypeDef structure
NVIC_InitTypeDef定义于文件“stm32f10x_nvic.h”:typedef struct
{
u8 NVIC_IRQChannel;
u8 NVIC_IRQChannelPreemptionPriority;
u8 NVIC_IRQChannelSubPriority;
FunctionalState NVIC_IRQChannelCmd;
} NVIC_InitTypeDef;
NVIC_IRQChannelPreemptionPriority
该参数设置了成员NVIC_IRQChannel中的先占优先级。
NVIC_IRQChannelSubPriority
该参数设置了成员NVIC_IRQChannel中的从优先级。
例:
NVIC_InitTypeDef NVIC_InitStructure;//定义NVIC初始化结构体
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //定义优先级字段
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQChannel; //选择设置TIM3全局中断NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//设置抢占优先级为0 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //设置次要优先级为2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;// 中断使能
NVIC_Init (&NVIC_InitStructure); //函数调用,按照初始化结构体设置相关寄存器6.3函数NVIC_StructInit
例:
NVIC_InitTypeDef structure
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_StructInit(&NVIC_InitStructure);//将相关寄存器设置为缺省值
6.4函数NVIC_SetVectorTable
#ifdef VECT_TAB_RAM
/* Set the Vector Table base location at 0x20000000 */ NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else /* VECT_TAB_FLASH */
/* Set the Vector Table base location at 0x08000000 */ NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
6.5函数NVIC_GenerateSystemReset
例:
/* Generate a system reset */
NVIC_GenerateSystemReset();
6.6函数NVIC_GenerateCoreReset
例:
/* Generate a core reset */
NVIC_GenerateCoreReset();
6.7函数NVIC_SystemLPConfig
例:
/* wakeup the system on interrupt pending */
NVIC_SystemLPConfig(SEVONPEND, ENABLE);
其他相关函数
以上七个函数为中断设置常用函数,以下为特殊的中断处理函数,仅描述出函数功能,具体使用情况请参考STM32F10xxx英文版固件函数库手册。
6.5函数NVIC_SETPRIMASK
功能描述:使能PRIMASK优先级:提升执行优先级至0
6.6函数NVIC_RESETPRIMASK
功能描述:失能PRIMASK优先级
6.7函数NVIC_SETFAULTMASK
功能描述:使能FAULTMASK优先级:提升执行优先级至-1
6.8函数NVIC_RESETFAULTMASK
功能描述:失能FAULTMASK优先级
6.9函数NVIC_BASEPRICONFIG
功能描述:改变执行优先级从N(最低可设置优先级)提升至1
6.10函数NVIC_GetBASEPRI
功能描述:返回BASEPRI屏蔽值
6.11函数NVIC_GetCurrentPendingIRQChannel
功能描述:返回当前待处理IRQ标识符
6.12函数NVIC_GetIRQChannelPendingBitStatus
功能描述:检查指定的IRQ通道待处理位设置与否
6.13函数NVIC_SetIRQChannelPendingBit
功能描述:设置指定的IRQ通道待处理位
6.14函数NVIC_ClearIRQChannelPendingBit
功能描述:清除指定的IRQ通道待处理位
6.15函数NVIC_GetCurrentActiveHandler
功能描述:返回当前活动的Handler(IRQ通道和系统Handler)的标识符
6.16函数NVIC_GetIRQChannelActiveBitStatus
功能描述:检查指定的IRQ通道活动位设置与否
6.17函数NVIC_GetCPUID
功能描述:返回ID号码,Cortex-M3内核的版本号和实现细节
6.18函数NVIC_SystemHandlerConfig
功能描述:使能或者失能指定的系统Handler
6.19函数NVIC_SystemHandlerPriorityConfig
功能描述:设置指定的系统Handler优先级
6.20函数NVIC_GetSystemHandlerPendingBitStatus
功能描述:检查指定的系统Handler待处理位设置与否
6.21函数NVIC_SetSystemHandlerPendingBit
功能描述:设置系统Handler待处理位
6.22函数NVIC_ClearSystemHandlerPendingBit
功能描述:清除系统Handler待处理位
6.23函数NVIC_GetSystemHandlerActiveBitStatus
功能描述:检查系统Handler活动位设置与否
6.24函数NVIC_GetFaultHandlerSources
功能描述:返回表示出错的系统Handler源
6.25函数NVIC_GetFaultAddress
功能描述:返回产生表示出错的系统Handler所在位置的地址
七、程序设计
1、滴答时钟简单使用
①设计要求
配置系统嘀嗒时钟使之每毫秒产生一次中断,中断服务子程序为使PC6状态取反
②部分代码
Main.c文件中:
NVIC_InitTypeDef NVIC_InitStructure;/定义NVIC初始化结构体/
GPIO_InitTypeDef GPIO_InitStructure;//定义GPIO初始化结构体
EXTI_InitTypeDef EXTI_InitStructure;//定义EXTIC初始化结构体
NVIC_SetVectorTable(NVIC_V ectTab_RAM, 0x0); //分配中断向量表:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |
RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //抢占优先级字段0 次要优先级字段4
/*设置PC6口的最高输出频率为50M输入模式为推挽输出*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 ;//选择引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//设置最高输出频率
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//选择推挽输出模式
GPIO_Init(GPIOC, &GPIO_InitStructure);
void SysTick_Configuration(void)
{/* Select AHB clock(HCLK) as SysTick clock source */
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
/* Set SysTick Priority to 3 */
NVIC_SystemHandlerPriorityConfig(SystemHandler_SysTick, 3, 0);
/* SysTick interrupt each 1ms with HCLK equal to 72MHz */
SysTick_SetReload(350000);
/* Enable the SysTick Interrupt */
SysTick_ITConfig(ENABLE);
}
stm32f10x_it.c 文件中(中断服务子程序):
void SysTickHandler(void)
{ GPIO_WriteBit(GPIOC, GPIO_Pin_6, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_6)));
SysTick_CounterCmd(SysTick_Counter_Clear);
}
2、NVIC外部中断配置实验
①设计要求
设计一个中断优先级抢占的实例。设置二个中断:EXTI0和EXTI9,在EXTI9的中断服务子程序中实现EXTI0优先级别的改变,
②部分代码
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* Enable the EXTI9_5 Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure GPIOB Pin9 as input floating */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
/* Configure EXTI Line0 to generate an interrupt on falling edge */
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
/* Connect EXTI Line9 to PB.09 */
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource9);
/* Configure EXTI Line9 to generate an interrupt on falling edge */
EXTI_InitStructure.EXTI_Line = EXTI_Line9;
EXTI_Init(&EXTI_InitStructure);
stm32f10x_it.c 文件中(中断服务子程序):
void EXTI0_IRQHandler(void)
{
}
void EXTI9_5_IRQHandler(void)
{ NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
八、设计总结
在工控领域,用户要求具有更快的中断速度,Cortex-M3采用了Tail-Chaining中断技术,完全基于硬件进行中断处理,最多可减少12个时钟周期数,在实际应用中可减少70%中断。
Cortex-M3处理器和NVIC对所有优先级进行划分和处理。所有的异常处理均在Handle模式下进行。当出现异常时,处理器的状态被自动保存到栈中;在中断服务子程序结束之后,又会自动从栈中恢复处理器的状态。获取中断向量和状态保存是同时进行的,这提高了进入中断处理的效率。Cortex-M3处理器支持尾链技术,即当发生背靠背中断时,无需保存和恢复状态,而是继续执行。Cortex-M3处理器的一下特性,提高了处理异常的效率并降低了时间的延迟。