一、中断的概念
中断是指计算机运行过程中,出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行,示意图如下–来自百度百科
二、stm32f1xx体系结构
总线框架
stm32f1xx使用cortex-m3内核,并通过icode dcode system总线将外设扩展形成符合应用场景的MCU,如参考手册架构图
cortex-m3框架
其中的m3内核结构如下,其中包括的NVIC中嵌套向量中断控制器负责对cm3核外来自总线外设的中断进行管理,除了NVIC还包括:
SCB 系统控制块组件
SysTick 系统滴答定时器组件
CoreDebug 内核调试组件
ITM 指令跟踪宏单元
InterruptType 中断类型组件
MPU 内存保护单元(可选)
见core_cm3.h中对组件的寄存器地址定义
cortex-m3寄存器组
m3包括通用功能寄存器和特殊功能寄存器,如下:
其中PRIMASK、FAULTMASK、BASEPRI为中断屏蔽寄存器组;
PRIMASK :这是个只有 1 个位的寄存器。当它置 1 时,只剩下 NMI和硬 fault 可以响应, 关掉其它所有可屏蔽的异常,。它的缺省值是 0,表示没有关中断;
FAULTMASK:这是个只有 1 个位的寄存器。当它置 1 时,只有 NMI 才能响应,所有其它的异常,包括中断和 fault,都不能被响应。它的缺省值也是 0,表示没有关中断;
BASEPRI:这个寄存器最多有 9 位(由表达优先级的位数决定)。它定义了被屏蔽优先级的阈值。当它被设成某个值后,所有优先级号大于等于此值的中断都被关(优先级号越大,优先级越低)。但若被设成 0,则不关闭任何中断, 0为是缺省值,BASEPRI可以用在rtos中对一定范围实时性要求不高的中断进行屏蔽;
可见FAULTMASK是最彻底屏蔽中断的特殊功能寄存器;
三、stm32f1xx中断几个概念说明
异常/中断分类
按cm3手册系统异常支持编号1-15,编号16以上为外部中断,外部中断最多支持240个,即系统异常16个,外部中断240个,这里注意区分中断和异常是两个不同的概念他们的编号范围不同,如下图
其中Reset、NMI、Hard Fault的优先级不能被定义修改;
在头文件stm32f10x.h 中定义了中断编号枚举类型IRQn_Type,如下
typedef enum IRQn
{
/****** Cortex-M3 Processor Exceptions Numbers ***************************************************/
NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */
MemoryManagement_IRQn = -12, /*!< 4 Cortex-M3 Memory Management Interrupt */
BusFault_IRQn = -11, /*!< 5 Cortex-M3 Bus Fault Interrupt */
UsageFault_IRQn = -10, /*!< 6 Cortex-M3 Usage Fault Interrupt */
SVCall_IRQn = -5, /*!< 11 Cortex-M3 SV Call Interrupt */
DebugMonitor_IRQn = -4, /*!< 12 Cortex-M3 Debug Monitor Interrupt */
PendSV_IRQn = -2, /*!< 14 Cortex-M3 Pend SV Interrupt */
SysTick_IRQn = -1, /*!< 15 Cortex-M3 System Tick Interrupt */
/****** STM32 specific Interrupt Numbers *********************************************************/
WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */
PVD_IRQn = 1, /*!< PVD through EXTI Line detection Interrupt */
TAMPER_IRQn = 2, /*!< Tamper Interrupt */
RTC_IRQn = 3, /*!< RTC global Interrupt */
FLASH_IRQn = 4, /*!< FLASH global Interrupt */
RCC_IRQn = 5, /*!< RCC global Interrupt */
EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */
EXTI1_IRQn = 7, /*!< EXTI Line1 Interrupt */
EXTI2_IRQn = 8, /*!< EXTI Line2 Interrupt
--------省略-----------
} IRQn_Type;
从枚举中可知,定义时统一将上表的编号减了16,下面说明此点;
中断控制器
stm32f1xx内部采用cortex-m3内核,m3内核包含一个NVIC嵌套向量中断控制器,负责对最多240个外部中断的优先级、开关进行控制,对于15个系统异常并不由NVIC来控制,这点需要注意,NVIC的寄存器定义如下
typedef struct
{
__IO uint32_t ISER[8]; /*!< Offset: 0x000 Interrupt Set Enable Register */
uint32_t RESERVED0[24];
__IO uint32_t ICER[8]; /*!< Offset: 0x080 Interrupt Clear Enable Register */
uint32_t RSERVED1[24];
__IO uint32_t ISPR[8]; /*!< Offset: 0x100 Interrupt Set Pending Register */
uint32_t RESERVED2[24];
__IO uint32_t ICPR[8]; /*!< Offset: 0x180 Interrupt Clear Pending Register */
uint32_t RESERVED3[24];
__IO uint32_t IABR[8]; /*!< Offset: 0x200 Interrupt Active bit Register */
uint32_t RESERVED4[56];
__IO uint8_t IP[240]; /*!< Offset: 0x300 Interrupt Priority Register (8Bit wide) */
uint32_t RESERVED5[644];
__O uint32_t STIR; /*!< Offset: 0xE00 Software Trigger Interrupt Register */
} NVIC_Type;
IP[240]为中断优先级寄存器,每个中断最多使用8bit定义,IP数组大小为240 表示240个外部中断,由于数组下标只能从0开始,所以上对外部中断标号(16到255)统一减16之后从0开始到239,对应240数组大小,对于数组快速索引特性用查表法对寄存器索引便于配置;
ISER[8]为中断使能寄存器,240个中断每个占据1bit,一共需要7.5个32bit,取整为8个32bit,用于对外部中断进行使能和失能;
中断向量表
是一张表,可以理解为一个数组,每个表项(数组成员)为一个32bit数据,在stm32下32bit可以寻址4G空间中任何一个地址,这个地址为对应中断编号的函数(中断服务程序)的地址,中断向量表是可以重新映射的;
中断优先级/优先级分组
cm3内核最多支持256个可编程优先级,NVIC控制器的中断优先级寄存器uint8_t IP[240] 每个中断的宽度为8,实际在stm32f1中做了简化,只用了8位中的高四位定义优先级,同时定义了中断优先级分组的概念,优先级分组后可以有抢占优先级和子优先级进而进行中断嵌套的支持;优先级分组定义如下,见misc.h
The table below gives the allowed values of the pre-emption priority and subpriority according
to the Priority Grouping configuration performed by NVIC_PriorityGroupConfig function
============================================================================================================================
NVIC_PriorityGroup | NVIC_IRQChannelPreemptionPriority | NVIC_IRQChannelSubPriority | Description
============================================================================================================================
NVIC_PriorityGroup_0 | 0 | 0-15 | 0 bits for pre-emption priority
| | | 4 bits for subpriority
----------------------------------------------------------------------------------------------------------------------------
NVIC_PriorityGroup_1 | 0-1 | 0-7 | 1 bits for pre-emption priority
| | | 3 bits for subpriority
----------------------------------------------------------------------------------------------------------------------------
NVIC_PriorityGroup_2 | 0-3 | 0-3 | 2 bits for pre-emption priority
| | | 2 bits for subpriority
----------------------------------------------------------------------------------------------------------------------------
NVIC_PriorityGroup_3 | 0-7 | 0-1 | 3 bits for pre-emption priority
| | | 1 bits for subpriority
----------------------------------------------------------------------------------------------------------------------------
NVIC_PriorityGroup_4 | 0-15 | 0 | 4 bits for pre-emption priority
| | | 0 bits for subpriority
============================================================================================================================
NVIC_PriorityGroup_0 ((uint32_t)0x700) 表示有0个bit定义抢占优先级,4个bit定义子优先级bit7~ bit4,即没有抢占优先级,只有子优先级可定义优先级范围为0~15,数值越小优先级越高;
NVIC_PriorityGroup_1 ((uint32_t)0x600) 表示有1个bit定义抢占优先级bit7,3个bit定义子优先级bit6~ bit4,即抢占优先级范围为0~1,子优先级范围为0 ~7,数值越小优先级越高;
NVIC_PriorityGroup_2 ((uint32_t)0x500) 表示有2个bit定义抢占优先级bit7~ bit6,2个bit定义子优先级bit5~ bit4,即抢占优先级范围为0~3,子优先级范围为0 ~3,数值越小优先级越高;
NVIC_PriorityGroup_3 ((uint32_t)0x400) 表示有3个bit定义抢占优先级bit7~ bit5,1个bit定义子优先级bit4,即抢占优先级范围为0~7,子优先级范围为0 ~1,数值越小优先级越高;
NVIC_PriorityGroup_4 ((uint32_t)0x300) 表示有4个bit定义抢占优先级bit7~ bit4,0个bit定义子优先级,即没有子优先级,只有抢占优先级可定义优先级范围为0~15,数值越小优先级越高,在stm32f1xx使用rtos时会使用组4;
优先级分组的定义是统一定义,初始化后所有的外部中断使用相同的分组,使用m3内核的SCB组件的AIRCR寄存器的bit10~bit8来定义见函数 NVIC_PriorityGroupConfig;
中断嵌套
中断嵌套指一个低优先级中断可以被高优先级打断,高优先级
中断服务函数
中断服务函数为异常、外部中断触发后具体的业务处理所在的地方,一般包括清除中断标志位,处理具体的工作,函数执行完退出
四、中断配置/处理流程
外部中断
1、代码初始化执行一次优先级分组配置NVIC_PriorityGroupConfig,不配置采用默认配置;
2、配置某个中断号的优先级、使能,使用函数NVIC_Init,如USART1_IRQn;
3、对具体的中断号涉及的外设,在外设的寄存器上使能具体的中断,如USART1_IRQn中断号对应的串口外设支持接收非空、发送空等具体中断的配置使用USART_ITConfig;
4、具体中断号的对应的中断服务函数的业务处理编写;
注意:这里的外部中断指的是由cm3的NVIC管理的除系统异常的来自cm3外部的各种外设的中断,stm32f1xx有一个EXIT的外设(外部中断事件控制器),这里的外部EXIT指的是来自芯片外部通过芯片引脚进来的中断/事件,它也由NVIC进行管理;
系统异常
指的是不经过NVIC管理的cm3权威手册定义的1-15(在stm32f1xx下)下可以进行管理的如下中断号的异常 :
/****** Cortex-M3 Processor Exceptions Numbers ***************************************************/
NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */
MemoryManagement_IRQn = -12, /*!< 4 Cortex-M3 Memory Management Interrupt */
BusFault_IRQn = -11, /*!< 5 Cortex-M3 Bus Fault Interrupt */
UsageFault_IRQn = -10, /*!< 6 Cortex-M3 Usage Fault Interrupt */
SVCall_IRQn = -5, /*!< 11 Cortex-M3 SV Call Interrupt */
DebugMonitor_IRQn = -4, /*!< 12 Cortex-M3 Debug Monitor Interrupt */
PendSV_IRQn = -2, /*!< 14 Cortex-M3 Pend SV Interrupt */
SysTick_IRQn = -1, /*!< 15 Cortex-M3 System Tick Interrupt
常用的为systick作为系统滴答定时器可以在裸机下当定时器使用,也可以和pendsv一起在运行有类rtos的项目中使用;
配置syctick时使用SysTick_Config即可配置,其中调用NVIC_SetPriority对systick的优先级进行配置,NVIC_SetPriority函数中可以看到它的优先级不由NVIC来配置,而是由cm3中的SCB组件的SHP寄存器进行配置;
五、整体示意图
略