Interrupt Priority
- 1> STM32F103ZET6异常向量表
- 2> 中断优先级寄存器NVIC_IPRx
- 3> 中断优先级分组
- 4> 例程:设置EXTI4中断优先级
- 5> 例程:设置SysTick中断优先级
- 6> 为什么不能用NVIC_Init()设置Systick优先级?
- 7> 函数NVIC_EncodePriority()
1> STM32F103ZET6异常向量表
中断数量:70个
STM32F103ZET6有70个中断 = 60外设中断 + 10个系统中断;
问题来了:
70个中断中除了复位、NMI、硬件错误3个的中断优先级是固定的,
其他67个中断都可以改变,如何管理配置这些中断的优先级呢?
2> 中断优先级寄存器NVIC_IPRx
// core.cm3.h文件
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;
NVIC的中断优先级寄存器,有240个,位宽为8位,
每个中断都由一个8位来控制,也就是能控制240个中断,
STM32F103ZET6只有70个中断,够够的。
uint8_t IP[240];
STM32F103只使用优先级控制寄存器IPn的高4位[7:4]
3> 中断优先级分组
通过配置SCB中AIRCR中[10~8]3位来确定IP中高4位的分组模式;
高抢占优先级,可以【打断】低抢占优先级程序;
子优先级没有抢占功能,同一抢占级中,高子优先级的先执行;
// misc.h文件中:
#define NVIC_PriorityGroup_0 ((uint32_t)0x700) /*!< 0 bits for pre-emption priority
4 bits for subpriority */
#define NVIC_PriorityGroup_1 ((uint32_t)0x600) /*!< 1 bits for pre-emption priority
3 bits for subpriority */
#define NVIC_PriorityGroup_2 ((uint32_t)0x500) /*!< 2 bits for pre-emption priority
2 bits for subpriority */
#define NVIC_PriorityGroup_3 ((uint32_t)0x400) /*!< 3 bits for pre-emption priority
1 bits for subpriority */
#define NVIC_PriorityGroup_4 ((uint32_t)0x300) /*!< 4 bits for pre-emption priority
0 bits for subpriority */
4> 例程:设置EXTI4中断优先级
第1步:
先设置优先级分组模式,一般主程序中设置1次;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 中断优先级分组
第2步:
设置具体中断的抢占优先级,子优先级;
NVIC_InitTypeDef NVIC_tmp;
NVIC_tmp.NVIC_IRQChannel = EXTI4_IRQn; // 外部中断
NVIC_tmp.NVIC_IRQChannelPreemptionPriority = 0; // 抢占优先级
NVIC_tmp.NVIC_IRQChannelSubPriority = 0; // 子优先级
NVIC_tmp.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_tmp);
5> 例程:设置SysTick中断优先级
第1步:
先设置优先级分组模式,一般主程序中设置1次;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 中断优先级分组
第2步:
设置具体中断的抢占优先级,子优先级;
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_PriorityGroup_2, 0, 0));
6> 为什么不能用NVIC_Init()设置Systick优先级?
uint8_t NVIC_IRQChannel; 是无符号的成员变量,而SysTick_IRQn是【-1】,
并且也有注释,NVIC_IRQChannel这个结构体成员用于STM32的外设,
SysTick属于CPU部分,所以要调用NVIC_SetPriority();
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) */
// 省略其他成员定义
} NVIC_InitTypeDef;
7> 函数NVIC_EncodePriority()
函数功能:
根据优先级分组,抢占优先级,子优先级,生成优先级数字,
给NVIC_SetPriority() 函数用
// core_cm3.h
/**
* @brief Encode the priority for an interrupt
*
* @param PriorityGroup The used priority group
* @param PreemptPriority The preemptive priority value (starting from 0)
* @param SubPriority The sub priority value (starting from 0)
* @return The encoded priority for the interrupt
*
* Encode the priority for an interrupt with the given priority group,
* preemptive priority value and sub priority value.
* In case of a conflict between priority grouping and available
* priority bits (__NVIC_PRIO_BITS) the samllest possible priority group is set.
*
* The returned priority value can be used for NVIC_SetPriority(...) function
* 返回值用于NVIC_SetPriority();
*/
static __INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority)
{
uint32_t PriorityGroupTmp = (PriorityGroup & 0x07); /* only values 0..7 are used */
uint32_t PreemptPriorityBits;
uint32_t SubPriorityBits;
PreemptPriorityBits = ((7 - PriorityGroupTmp) > __NVIC_PRIO_BITS) ? __NVIC_PRIO_BITS : 7 - PriorityGroupTmp;
SubPriorityBits = ((PriorityGroupTmp + __NVIC_PRIO_BITS) < 7) ? 0 : PriorityGroupTmp - 7 + __NVIC_PRIO_BITS;
return (
((PreemptPriority & ((1 << (PreemptPriorityBits)) - 1)) << SubPriorityBits) |
((SubPriority & ((1 << (SubPriorityBits )) - 1)))
);
}