当前位置: 首页 > news >正文

MCU_ARM-CORTEX-M0中断优先级设置及NVIC_SetPriority解读

参考资料

参考:《Cortex-M0+ Devices Generic User Guide》

http://www.keil.com/dd/docs/datashts/arm/cortex_m0p/r0p0/dui0662a_cortex_m0p_r0p0_dgug.pdf

http://infocenter.arm.com/help/topic/com.arm.doc.dui0497a/DUI0497A_cortex_m0_r0p0_generic_ug.pdf

表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解读

我们看一下一些相关定义:

​stm32f0xx.h​​​​​


/**
 * @brief STM32F0xx Interrupt Number Definition, according to the selected device 
 *        in @ref Library_configuration_section 
 */
#define __CM0_REV                 0 /*!< Core Revision r0p0                            */
#define __MPU_PRESENT             0 /*!< STM32F0xx do not provide MPU                  */
#define __NVIC_PRIO_BITS          2 /*!< STM32F0xx uses 2 Bits for the Priority Levels */
#define __Vendor_SysTickConfig    0 /*!< Set to 1 if different SysTick Config is used  */

/*!< 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)); }
  else {
    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]; /*!< Offset: 0x000 (R/W)  Interrupt Set Enable Register*/
       uint32_t RESERVED0[31];
  __IO uint32_t ICER[1]; /*!< Offset: 0x080 (R/W)  Interrupt Clear Enable Register*/
       uint32_t RSERVED1[31];
  __IO uint32_t ISPR[1]; /*!< Offset: 0x100 (R/W)  Interrupt Set Pending Register*/
       uint32_t RESERVED2[31];
  __IO uint32_t ICPR[1]; /*!< Offset: 0x180 (R/W)  Interrupt Clear Pending Register */
       uint32_t RESERVED3[31];
       uint32_t RESERVED4[64];
  __IO uint32_t IP[8];   /*!< Offset: 0x300 (R/W)  Interrupt Priority Register  */
}  NVIC_Type;


/* Interrupt Priorities are WORD accessible only under ARMv6M                   */
/* The following MACROS handle generation of the register offset 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);

相关文章:

  • MCU_单片机开发几个常用的IDE
  • MCU_STM32F4XX 的中断优先级(和STM32F1XX相同)
  • MCU_STM32的位带操作 -- bit banding
  • C++的问题:变量“xxx”不是类型名
  • UInt8, UInt16, UInt32, UInt64, Int8, Int16, Int32, Int64, FLOAT, DOUBLE
  • c++ 如何给数组批量赋值--利用结构定义数组以提高程序的可读性
  • c++ windows 之下 CreateThread vs CreateProcess
  • libusb源码学习:list_entry
  • libusb源码学习:几个函数加载的宏(windows)
  • MCU_如何通过硬件VID 查找生产厂家
  • MCU_WireShark USB抓包内容解析
  • MCU_Wireshark USB 抓包过滤(抓特定端口地址)
  • STM32F4xx usb库源码详解 custom HID
  • STM32F4xx usb库源码详解:HAL_PCDEx_SetRxFiFo 和 HAL_PCDEx_SetTxFiFo
  • Libuv 1.34.2 源码详解 ---- 以uvCat为例讲解
  • 「前端早读君006」移动开发必备:那些玩转H5的小技巧
  • 【翻译】Mashape是如何管理15000个API和微服务的(三)
  • Android 初级面试者拾遗(前台界面篇)之 Activity 和 Fragment
  • angular2开源库收集
  • Intervention/image 图片处理扩展包的安装和使用
  • JavaScript设计模式之工厂模式
  • java小心机(3)| 浅析finalize()
  • js写一个简单的选项卡
  • PAT A1120
  • React as a UI Runtime(五、列表)
  • Zsh 开发指南(第十四篇 文件读写)
  • 编写高质量JavaScript代码之并发
  • 给初学者:JavaScript 中数组操作注意点
  • 机器学习 vs. 深度学习
  • 极限编程 (Extreme Programming) - 发布计划 (Release Planning)
  • 如何优雅地使用 Sublime Text
  • 深度学习在携程攻略社区的应用
  • 事件委托的小应用
  • 微服务核心架构梳理
  • 微信小程序实战练习(仿五洲到家微信版)
  • 白色的风信子
  • 长三角G60科创走廊智能驾驶产业联盟揭牌成立,近80家企业助力智能驾驶行业发展 ...
  • ​【已解决】npm install​卡主不动的情况
  • ​Python 3 新特性:类型注解
  • # 深度解析 Socket 与 WebSocket:原理、区别与应用
  • #每日一题合集#牛客JZ23-JZ33
  • ${ }的特别功能
  • (1) caustics\
  • (6)设计一个TimeMap
  • (9)YOLO-Pose:使用对象关键点相似性损失增强多人姿态估计的增强版YOLO
  • (论文阅读11/100)Fast R-CNN
  • (十八)三元表达式和列表解析
  • (转)人的集合论——移山之道
  • ***linux下安装xampp,XAMPP目录结构(阿里云安装xampp)
  • ***汇编语言 实验16 编写包含多个功能子程序的中断例程
  • .htaccess配置常用技巧
  • .Net Core webapi RestFul 统一接口数据返回格式
  • .NET 回调、接口回调、 委托
  • .net 简单实现MD5
  • .netcore 获取appsettings