MCU_ARM-CORTEX-M0中断优先级设置及NVIC_SetPriority
解读
参考资料
参考:《Cortex-M0+ Devices Generic Ur Guide》
表4.2.6
公鸡晚上打鸣是怎么回事
要注意的⼏点:
(1)Cortex-M0中NVIC-IPR共有8个寄存器,⽽每个寄存器管理4个IRQ中断,所以M0+的IRQ中断源最多只⽀持32个了,再加上16个内核中断,也就是说M0+最多就是48个中断源;
(2)优先级寄存器⾥⾯的配置值越低表明相应的中断优先级越⾼;
(3)每个PRIxx的8位中只有最⾼两位[7:6]有效,也就是说实际上M0+的优先级只有四个即0,1,2,3,其中0的优先级是最⾼的;
(4)这是⽐较容易忽略的问题,即word-accessible,也就是说这⼏个寄存器都只能按字操作,切记不要使⽤指向字节的指针只对某个单独中断的优先级进⾏配置。
(5)M0的嵌套相对⽐较简单,即只要相应中断的优先级⽐较⾼即可随时抢占⽐它优先级低的中断服务。
(6)内核中断,其中断优先级则由SCB模块的SCB_SHPR寄存器来管理,可参考⼿册4.3.7 System Handler Priority Registers,实际上我们平时常⽤的就是systemtick中断,其优先级配置同NVIC。
另外,如果我们不对优先级进⾏配置的话,则默认相应中断源的向量号越低其优先级越⾼。
NVIC_SetPriority解读
我们看⼀下⼀些相关定义:
s tm32f0xx.h
/**
* @brief STM32F0xx Interrupt Number Definition, according to the lected device
* in @ref Library_configuration_ction
*/
#define __CM0_REV 0 /*!< Core Revision r0p0 */
#define __MPU_PRESENT 0 /*!< STM32F0xx do not provide MPU */
#define __NVIC_PRIO_BITS 2 /*!< STM32F0xx us 2 Bits for the Priority Levels */
#define __Vendor_SysTickConfig 0 /*!< Set to 1 if different SysTick Config is ud */
64年/
*!< Interrupt Number Definition */
typedef enum IRQn
{
/****** Cortex-M0 Processor Exceptions Numbers ******************************************************/
NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */
HardFault_IRQn = -13, /*!< 3 Cortex-M0 Hard Fault Interrupt */
SVC_IRQn = -5, /*!< 11 Cortex-M0 SV Call Interrupt */
PendSV_IRQn = -2, /*!< 14 Cortex-M0 Pend SV Interrupt */
SysTick_IRQn = -1, /*!< 15 Cortex-M0 System Tick Interrupt */
/****** STM32F-0 specific Interrupt Numbers *********************************************************/
WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */
PVD_IRQn = 1, /*!< PVD through EXTI Line detect Interrupt */
RTC_IRQn = 2, /*!< RTC through EXTI Line Interrupt*/
FLASH_IRQn = 3, /*!< FLASH Interrupt*/
RCC_IRQn = 4, /*!< RCC Interrupt*/
EXTI0_1_IRQn = 5, /*!< EXTI Line 0 and 1 Interrupts */
EXTI2_3_IRQn = 6, /*!< EXTI Line 2 and 3 Interrupts */
EXTI4_15_IRQn = 7, /*!< EXTI Line 4 to 15 Interrupts */
TS_IRQn = 8, /*!< TS Interrupt*/
DMA1_Channel1_IRQn = 9, /*!< DMA1 Channel 1 Interrupt */
DMA1_Channel2_3_IRQn = 10, /*!< DMA1 Channel 2 and Channel 3 Interrupts */
DMA1_Channel4_5_IRQn = 11, /*!< DMA1 Channel 4 and Channel 5 Interrupts*/
ADC1_COMP_IRQn = 12, /*!< ADC1, COMP1 and COMP2 Interrupts*/
TIM1_BRK_UP_TRG_COM_IRQn = 13, /*!< TIM1 Break, Update, Trigger and Commutation Interrupts */ TIM1_CC_IRQn = 14, /*!< TIM1 Capture Compare Interrupt */
TIM2_IRQn = 15, /*!< TIM2 Interrupt */
TIM3_IRQn = 16, /*!< TIM3 Interrupt */
TIM6_DAC_IRQn = 17, /*!< TIM6 and DAC Interrupts*/
TIM14_IRQn = 19, /*!< TIM14 Interrupt */
TIM15_IRQn = 20, /*!< TIM15 Interrupt */
TIM16_IRQn = 21, /*!< TIM16 Interrupt */
TIM17_IRQn = 22, /*!< TIM17 Interrupt */
I2C1_IRQn = 23, /*!< I2C1 Interrupt */
I2C2_IRQn = 24, /*!< I2C2 Interrupt*/
爱莲说仿写>君子兰不开花是什么原因
SPI1_IRQn = 25, /*!< SPI1 Interrupt*/
SPI2_IRQn = 26, /*!< SPI2 Interrupt */
USART1_IRQn = 27, /*!< USART1 Interrupt*/
USART2_IRQn = 28, /*!< USART2 Interrupt */
CEC_IRQn = 30 /*!< CEC Interrupt */
} IRQn_Type;
static __INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
if(IRQn < 0) {
SCB->SHP[_SHP_IDX(IRQn)] = (SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFF << _BIT_SHIFT(IRQn))) |
(((priority << (8 - __NVIC_PRIO_BITS)) & 0xFF) << _BIT_SHIFT(IRQn)); }
el {
爱人的诗句NVIC->IP[_IP_IDX(IRQn)] = (NVIC->IP[_IP_IDX(IRQn)] & ~(0xFF << _BIT_SHIFT(IRQn))) |
(((priority << (8 - __NVIC_PRIO_BITS)) & 0xFF) << _BIT_SHIFT(IRQn)); }
}
core_cm0.h
/** \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC).*/
typedef struct
{
__IO uint32_t ISER[1]; /*!< Offt: 0x000 (R/W) Interrupt Set Enable Register*/
uint32_t RESERVED0[31];
__IO uint32_t ICER[1]; /*!< Offt: 0x080 (R/W) Interrupt Clear Enable Register*/
uint32_t RSERVED1[31];
__IO uint32_t ISPR[1]; /*!< Offt: 0x100 (R/W) Interrupt Set Pending Register*/
uint32_t RESERVED2[31];
__IO uint32_t ICPR[1]; /*!< Offt: 0x180 (R/W) Interrupt Clear Pending Register */
全人uint32_t RESERVED3[31];
uint32_t RESERVED4[64];
__IO uint32_t IP[8]; /*!< Offt: 0x300 (R/W) Interrupt Priority Register */
} NVIC_Type;
/* Interrupt Priorities are WORD accessible only under ARMv6M */
/* The following MACROS handle generation of the register offt and byte masks */
#define _BIT_SHIFT(IRQn) ( (((uint32_t)(IRQn) ) & 0x03) * 8 )
#define _SHP_IDX(IRQn) ( ((((uint32_t)(IRQn) & 0x0F)-8) >> 2) )
#define _IP_IDX(IRQn) ( ((uint32_t)(IRQn) >> 2) )
计算⽅法举例,如:
NVIC_SetPriority(SPI1_IRQn, 0x25);
实际计算的是
校园消防安全宣传图片NVIC->IP[6] = (NVIC->IP[6] & ~(0xFF << _BIT_SHIFT(IRQn))) |
(((priority << (8 - __NVIC_PRIO_BITS)) & 0xFF) << _BIT_SHIFT(IRQn));
计算中⽤到的⼀些结果(⾃⼰⼿动算⼀次就明⽩了):
SPI1_IRQn = 25 = 0b11001
_IP_IDX(IRQn) = 6
_BIT_SHIFT(IRQn) = (0x25&0x03)*8 = 8
这样的拼音~
(0xFF << _BIT_SHIFT(IRQn) = ~0x0000FF00= 0xFFFF00FF
因此,(NVIC->IP[6] & ~(0xFF << _BIT_SHIFT(IRQn)))就是清零的意思,后⾯
(priority << (8 - __NVIC_PRIO_BITS) = 25<<6 = 0b11001000000=0x640
(priority << (8 - __NVIC_PRIO_BITS) &0xFf = 0x040
所以下⾯这句就是priority选最低两位, 然后左移到相应的4个IPR寄存器中的⼀个。⽐如SPI1_IRQn在第2个,(((priority << (8 - __NVIC_PRIO_BITS)) & 0xFF) << _BIT_SHIFT(IRQn)) = 0x04000
因此,NVIC->IP[6]中第25个中断的优先级是0x25的有效最低两位,即0x01
所以,下⾯两个设置是完全等价的
NVIC_SetPriority(SPI1_IRQn, 0x25);
NVIC_SetPriority(SPI1_IRQn, 0x01);