CM3内核支持256个中断,16个内核中断和240个外部中断,具有256级可编程中断设置
STM32只使用了CM3内核的一部分,84个中断:16个内核中断+68个可屏蔽中断(外部中断),具有16级可编程的中断优先级
STM32F103系列只有60个可屏蔽中断(F107系列有68个)
STM32有如此多的中断,那么是如何进行管理的
中断优先级分组:
SCB->AIRCR [10:8]3位寄存器 :
配置分组,确定中断具有几位抢占优先级和几位响应优先级
每一个中断都具有一个[7:4]4位IP寄存器,通过这4个位来设置抢占和响应优先级, 16级可编程中断优先级(2的4次方=16)
配置分组寄存器SCB->AIRCR之后,抢占优先级和响应优先级的位分配也对应完成
优先级高低划分:0最高,4最低
较高抢占优先级中断可以打断正在执行的较低抢占优先级的中断
如:A的抢占优先级是4,B的抢占优先级是0
A中断正在执行中,B中断发生,此时由于B的抢占优先级较高,会先暂停执行A的中断,先执行B的中断,待B中中断执行完成后,继续执行A的中断
抢占优先级相同,且两个中断同时发生时,响应优先级较高的中断先执行
如:A,B的抢占优先级是0,A的响应优先级是0,B的响应优先级是4
A,B中断同时发生,此时由于A的响应优先级较高,A中断先执行
中断优先级分组函数:
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
在misc.c中找到NVIC_PriorityGroupConfig函数源码:
/**
* @brief Configures the priority grouping: pre-emption priority and subpriority.
* @param NVIC_PriorityGroup: specifies the priority grouping bits length.
* This parameter can be one of the following values:
* @arg NVIC_PriorityGroup_0: 0 bits for pre-emption priority
* 4 bits for subpriority
* @arg NVIC_PriorityGroup_1: 1 bits for pre-emption priority
* 3 bits for subpriority
* @arg NVIC_PriorityGroup_2: 2 bits for pre-emption priority
* 2 bits for subpriority
* @arg NVIC_PriorityGroup_3: 3 bits for pre-emption priority
* 1 bits for subpriority
* @arg NVIC_PriorityGroup_4: 4 bits for pre-emption priority
* 0 bits for subpriority
* @retval None
*/
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
{
/* Check the parameters */
assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup));
/* Set the PRIGROUP[10:8] bits according to NVIC_PriorityGroup value */
SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup; //实际操作了SCB->AIRCR寄存器
}
入参NVIC_PriorityGroup有效性判断:
在misc.h中找到IS_NVIC_PRIORITY_GROUP的声明
/** @defgroup Preemption_Priority_Group
* @{
*/
#define NVIC_PriorityGroup_0 ((uint32_t)0x700) //0位抢占,1为响应
#define NVIC_PriorityGroup_1 ((uint32_t)0x600) //1位抢占,3为响应
#define NVIC_PriorityGroup_2 ((uint32_t)0x500) //2位抢占,2为响应
#define NVIC_PriorityGroup_3 ((uint32_t)0x400) //3位抢占,1为响应
#define NVIC_PriorityGroup_4 ((uint32_t)0x300) //4位抢占,0为响应
//有效性 分组0 - 分组4
#define IS_NVIC_PRIORITY_GROUP(GROUP) (((GROUP) == NVIC_PriorityGroup_0) || \
((GROUP) == NVIC_PriorityGroup_1) || \
((GROUP) == NVIC_PriorityGroup_2) || \
((GROUP) == NVIC_PriorityGroup_3) || \
((GROUP) == NVIC_PriorityGroup_4))
设置分组:
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//分组2
__IO uint8_t IP[240]; //中断优先级控制的寄存器组
__IO uint32_t ISER[8]; //中断使能寄存器组
__IO uint32_t ICER[8]; //中断失能寄存器组
__IO uint32_t ISPR[8]; //中断挂起寄存器组
__IO uint32_t ICPR[8]; //中断解挂寄存器组
__IO uint32_t IABR[8]; //中断激活标志位寄存器组
中断优先级分组属于内核级别,在core_cm3.h中找到NVIC_Type结构体
/** @addtogroup CMSIS_CM3_NVIC CMSIS CM3 NVIC
memory mapped structure for Nested Vectored Interrupt Controller (NVIC)
@{
*/
typedef struct
{
__IO uint32_t ISER[8]; /*!< Offset: 0x000 中断使能寄存器组 */
uint32_t RESERVED0[24];
__IO uint32_t ICER[8]; /*!< Offset: 0x080 中断失能寄存器组 */
uint32_t RSERVED1[24];
__IO uint32_t ISPR[8]; /*!< Offset: 0x100 中断挂起寄存器组 */
uint32_t RESERVED2[24];
__IO uint32_t ICPR[8]; /*!< Offset: 0x180 中断解挂寄存器组 */
uint32_t RESERVED3[24];
__IO uint32_t IABR[8]; /*!< Offset: 0x200 中断激活标志位寄存器组 */
uint32_t RESERVED4[56];
__IO uint8_t IP[240]; /*!< Offset: 0x300 中断优先级控制的寄存器组(8Bit wide) */
uint32_t RESERVED5[644];
__O uint32_t STIR; /*!< Offset: 0xE00 Software Trigger Interrupt Register */
} NVIC_Type;
1,中断优先级控制的寄存器组 IP[240]
IP[240]寄存器组,对于每个中断都有一个IP寄存器,共240个8位寄存器
CM3内核最多有240个可屏蔽中断,所以有240个8位寄存器来配置240个中断的优先级
STM32F10x系列共60个可屏蔽中断,使用IP[59]-IP[0]
每个IP寄存器的高4位用于设置抢占和响应优先级.低4位没有用到
通过NVIC_Init()函数设置抢占和响应优先级
在misc.h中找到NVIC_Init()函数源码:
/**
* @brief Initializes the NVIC peripheral according to the specified
* parameters in the NVIC_InitStruct.
* @param NVIC_InitStruct: pointer to a NVIC_InitTypeDef structure that contains
* the configuration information for the specified NVIC peripheral.
* @retval None
*/
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
{
uint32_t tmppriority = 0x00, tmppre = 0x00, tmpsub = 0x0F;
/* Check the parameters */
assert_param(IS_FUNCTIONAL_STATE(NVIC_InitStruct->NVIC_IRQChannelCmd));
assert_param(IS_NVIC_PREEMPTION_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority));
assert_param(IS_NVIC_SUB_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelSubPriority));
if (NVIC_InitStruct->NVIC_IRQChannelCmd != DISABLE)
{
/* Compute the Corresponding IRQ Priority --------------------------------*/
tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08;
tmppre = (0x4 - tmppriority);
tmpsub = tmpsub >> tmppriority;
tmppriority = (uint32_t)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre;
tmppriority |= NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub;
tmppriority = tmppriority << 0x04;
NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel] = tmppriority;
/* Enable the Selected IRQ Channels --------------------------------------*/
NVIC->ISER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =
(uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);
}
else
{
/* Disable the Selected IRQ Channels -------------------------------------*/
NVIC->ICER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =
(uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);
}
}
参数NVIC_InitTypeDef*结构体指针,位于misc.h
typedef struct
{
uint8_t NVIC_IRQChannel; //设置中断通道
uint8_t NVIC_IRQChannelPreemptionPriority;//设置响应优先级
uint8_t NVIC_IRQChannelSubPriority; //设置抢占优先级
FunctionalState NVIC_IRQChannelCmd; //使能/使能
} NVIC_InitTypeDef;
/** @addtogroup STM32F10x_StdPeriph_Driver
* @{
*/
/** @addtogroup MISC
* @{
*/
/** @defgroup MISC_Exported_Types
* @{
*/
/**
* @brief NVIC Init Structure definition
*/
typedef struct
{
uint8_t NVIC_IRQChannel; /*!< Specifies the IRQ channel to be enabled or disabled.
This parameter can be a value of @ref IRQn_Type
(For the complete STM32 Devices IRQ Channels list, please
refer to stm32f10x.h file) */
//通道
uint8_t NVIC_IRQChannelPreemptionPriority; /*!< Specifies the pre-emption priority for the IRQ channel
specified in NVIC_IRQChannel. This parameter can be a value
between 0 and 15 as described in the table @ref NVIC_Priority_Table */
//抢占优先级
uint8_t NVIC_IRQChannelSubPriority; /*!< Specifies the subpriority level for the IRQ channel specified
in NVIC_IRQChannel. This parameter can be a value
between 0 and 15 as described in the table @ref NVIC_Priority_Table */
//响应优先级
FunctionalState NVIC_IRQChannelCmd; /*!< Specifies whether the IRQ channel defined in NVIC_IRQChannel
will be enabled or disabled.
This parameter can be set either to ENABLE or DISABLE */
//使能
} NVIC_InitTypeDef;
2,中断使能寄存器组 ISER[8]
ISER[8]寄存器组 : 8个32位寄存器,每个位控制一个中断的使能
STM32F10x有60个可屏蔽中断,所以只使用到了ISER[0]和 ISER[1]
ISER[0]的bit0-bit31对应中断0-31,ISER[1]的bit0-27对应中断32-59
3,中断失能寄存器组 ICER[8]
ICER[8]寄存器组 : 8个32位寄存器,每个位控制一个中断的失能
STM32F10x有60个可屏蔽中断,所以只使用到了ICER[0]和 ICER[1]
ICER[0]的bit0-bit31对应中断0-31,ISER[1]的bit0-27对应中断32-59
4,中断挂起控制寄存器组 ISPR[8]
作用:挂起中断
static __INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn)
{
/* Return 1 if pending else 0 */
return((uint32_t) ((NVIC->ISPR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0));
}
static __INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn)
{
/* set interrupt pending */
NVIC->ISPR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
}
5,中断解挂控制寄存器组 ICPR[8]
作用:用来解挂中断
static __INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn)
{
/* Clear pending interrupt */
NVIC->ICPR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
}
6,中断激活标志位寄存器组: IABR[8]
IABR[8]寄存器组: 8个32位寄存器,每个位控制一个中断激活标志位
F10x只有60个可屏蔽中断,只用到了 IABR[0] IABR[1]
IABR[0]的bit0-bit31对应中断0-31,IABR[1]的bit0-27对应中断32-59
作用:只读,通过它可以知道当前在执行的中断是哪一个,如果对应位为1,说明该中断正在执行
static __INLINE uint32_t NVIC_GetActive(IRQn_Type IRQn)
{
/* Return 1 if active else 0 */
return((uint32_t)((NVIC->IABR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0));
}
中断初始化步骤
1,定义结构体变量
2,配置中断
配置哪个中断
配置抢占优先级
配置响应优先级
配置使能
3,地址赋值给初始化函数
中断优先级设置步骤
系统运行后,先设置中断优先级分组
调用函数: void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
系统执行过程中,只设置一个中断分组
针对每个中断,设置对应的抢占优先级和响应优先级
调用函数:`void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);`
如果需要挂起/解挂,查看中断当前激活状态,分别调用相关函数即可
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //串口1中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ; // 抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; // 子优先级(响应)为2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据上面指定的参数初始化NVIC寄存器