NVIC中断优先级管理

一,STM32中断介绍

CM3内核支持256个中断,16个内核中断和240个外部中断,具有256级可编程中断设置

STM32只使用了CM3内核的一部分,84个中断:16个内核中断+68个可屏蔽中断(外部中断),具有16级可编程的中断优先级

STM32F103系列只有60个可屏蔽中断(F107系列有68个)


二,中断管理

STM32有如此多的中断,那么是如何进行管理的

NVIC中断优先级管理_第1张图片

中断优先级分组:

 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寄存器

你可能感兴趣的:(STM32,STM32学习笔记)