你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32经验分享 第10章 基础重点—中断系统

[复制链接]
STMCU小助手 发布时间:2022-8-30 18:22
10.1 Cortex-M3的中断和优先级
正常情况下,微处理器根据代码内容,按顺序执行指令。执行过程中,如果遇到其它紧急的事件需要处理,则先暂停当前任务,执行紧急事件,待紧急事件处理完后,再恢复到刚才暂停的地方继续执行。这个产生的紧急事件就叫做中断或异常,如图 10.1.1 所示。
UB(OY4CG4BO58T%[)@2LY[A.png


图 10.1.1 中断或异常处理示意图

通常,把CPU内部产生的紧急事件叫做异常,比如非法指令(除零)、地址访问越界等;把来自CPU外部的片上外设产生的紧急事件叫做中断,比如GPIO引脚电平变化、定时器溢出等。异常和中断的效果基本一致,都是暂停当前任务,优先执行紧急事件,因此一般将中断和异常统称为中断。

ARM公司设计了Cortex-M3内核,这个内核就包含了中断系统框架,对应资料“2_原厂资料\10.0_Cortex-M3权威指南.pdf”,后简称《CM3权威指南》。

ST公司根据该内核,因地制宜的设计了STM32系列产品,对应资料“2_原厂资料\3_STM32F10xx Cortex-M3编程手册.pdf”,后简称《CM3编程手册》。

《CM3权威指南》讲解的是Cortex-M3内核的整个体系,例如指令集、异常、MPU等,《CM3编程手册》中则是关于STM32F10/20/21/L1系列使用到的Cortex-M3的内容。换句话说《CM3编程手册》是《CM3权威指南》的一个子集,本章内容就是参考这两个手册,对于本章没提到的内容,读者可自行阅读这两个手册扩展学习。

Cortex-M3内核有256种异常和中断,其中编号1~15是系统异常,16~256是外部中断,如下表 10.1.1 所示。

Q76M~CR(0$[VL}J_$R]X80E.png


表 10.1.1 Cortex-M3中断异常表

如此多的中断,导致了一些新问题。比如两个中断同时发生,应该先执行哪个中断任务?又比如一个中断发生了,又来了一个更紧急的中断,是该继续执行原来的中断,还是执行新的紧急中断?

针对这些问题,Cortex-M3内核有一个专门管理中断的外设NVIC(Nested Vectored Interrupt Controller,嵌套向量中断控制器),通过优先级控制中断的嵌套和调度。NVIC是一个总的中断控制器,无论是来在内核的异常还是外设的外部中断,都由NVIC统一进行管理。

上表 10.1.1 中,Reset(复位)、NMI(Non Maskable Interrupt,不可屏蔽中断)、HardFault(硬件异常)的优先级是固定的,且优先级是负数,也就是最高的(优先级数字越小,优先级越高)。剩下的异常或中断,都是可以通过修改NVIC的寄存器调整优先级(但不能设置为负数)。NVIC作为在内核里的外设,也是通过存储器映射的方式访问,对应表 6.1.1 中的Block7。

在Cortex-M3中,将优先级拆分为抢占优先级(Preempt Priority)和子优先级(Subpriority),每个中断都需要指定这两级,具有高优先级的中断可以打断低优先级的中断,实现中断嵌套。

通过应用中断和复位控制寄存器(Application Interrupt and Reset Control Register,AIRCR)的Bits[10:8](PRIGROUP)将优先级分组。分组决定每个可编程中断的PRI_n的Bits[7:0]的高低位分配,从而影响抢占优先和子优先级的级数,两者关系如表 10.1.2 所示。

99_A)JZD~%{ZQ8C5[46`3~K.png


表 10.1.2 Cortex-M3优先级分组

举个例子,假设将优先级分组(PRIGROUP)设置为2,此时每个中断可设置抢占优先级范围为0~32,子优先级范围为0~8,比如某中断的抢占优先级为2,子优先级为3。

所有可编程的中断都需要指定抢占优先级和子优先级,抢占优先级决定是否可以产生中断嵌套,子优先级决定中断响应顺序,若两种优先级一样则看中断在中断异常表中的位置,越靠前越先响应。

抢占优先级高(值小)的中断可以中断抢占优先级低(值大)的中断处理函数,进而执行高优先级的中断处理函数,执行完毕后再继续执行被中断的低优先级的处理函数。

当两个中断的抢占优先级相同时,即这两个中断将没有嵌套关系,当一个中断到来后,若此时CPU正在处理另一个中断,则这个后到来的中断就要等到前一个中断处理函数处理完毕后才能被处理,当这两个中断同时到达,则中断控制器会根据它们的子优先级决定先处理哪个。

如果两个中断的优先级都设置为一样了,那么谁先触发的就谁先执行;如果是同时触发的,那么就根据中断异常表的位置(靠前)来决定谁先执行。

在大概了解Cortex-M3内核的异常和中断及其优先级之后,再来看看STM32对Cortex-M3的这些异常和中断做了哪些裁剪,又有何特点。



10.2 STM32的中断和优先级
由表 10.1.1 可知,Cortex-M3设计有256种中断,但大多数MCU都用不到这么多中断,比如STM32F103系列就最多只有70种异常和中断,其中前10个是系统异常,后面60个是外部中断,如下表 10.2.1 所示。

%__ED`5A8)U]NIFQ{52IM8K.png


表 10.2.1 STM32F103中断异常表

在HAL库启动文件“startup_stm32f103xb.s”,可以看到定义的中断向量表,如代码段 10.2.1 所示。

代码段 10.2.1  STM32F103x8中断向量表(startup_stm32f103xb.s)

  1. __Vectors       DCD     __initial_sp               ; Top of Stack

  2.                 DCD     Reset_Handler              ; Reset Handler

  3.                 DCD     NMI_Handler                ; NMI Handler

  4.                 DCD     HardFault_Handler          ; Hard Fault Handler

  5.                 DCD     MemManage_Handler          ; MPU Fault Handler

  6.                 DCD     BusFault_Handler           ; Bus Fault Handler

  7.                 DCD     UsageFault_Handler         ; Usage Fault Handler

  8.                 DCD     0                          ; Reserved

  9.                 DCD     0                          ; Reserved

  10.                 DCD     0                          ; Reserved

  11.                 DCD     0                          ; Reserved

  12.                 DCD     SVC_Handler                ; SVCall Handler

  13.                 DCD     DebugMon_Handler           ; Debug Monitor Handler

  14.                 DCD     0                          ; Reserved

  15.                 DCD     PendSV_Handler             ; PendSV Handler

  16.                 DCD     SysTick_Handler            ; SysTick Handler



  17.                 ; External Interrupts

  18.                 DCD     WWDG_IRQHandler            ; Window Watchdog

  19.                 DCD     PVD_IRQHandler             ; PVD through EXTI Line detect

  20.                 DCD     TAMPER_IRQHandler          ; Tamper

  21.                 DCD     RTC_IRQHandler             ; RTC

  22.                 DCD     FLASH_IRQHandler           ; Flash

  23.                 DCD     RCC_IRQHandler             ; RCC

  24.                 DCD     EXTI0_IRQHandler           ; EXTI Line 0

  25.                 DCD     EXTI1_IRQHandler           ; EXTI Line 1

  26.                 DCD     EXTI2_IRQHandler           ; EXTI Line 2

  27.                 DCD     EXTI3_IRQHandler           ; EXTI Line 3

  28.                 DCD     EXTI4_IRQHandler           ; EXTI Line 4

  29.                 DCD     DMA1_Channel1_IRQHandler   ; DMA1 Channel 1

  30.                 DCD     DMA1_Channel2_IRQHandler   ; DMA1 Channel 2

  31.                 DCD     DMA1_Channel3_IRQHandler   ; DMA1 Channel 3

  32.                 DCD     DMA1_Channel4_IRQHandler   ; DMA1 Channel 4

  33.                 DCD     DMA1_Channel5_IRQHandler   ; DMA1 Channel 5

  34.                 DCD     DMA1_Channel6_IRQHandler   ; DMA1 Channel 6

  35.                 DCD     DMA1_Channel7_IRQHandler   ; DMA1 Channel 7

  36.                 DCD     ADC1_2_IRQHandler          ; ADC1 & ADC2

  37.                 DCD     USB_HP_CAN1_TX_IRQHandler  ; USB High Priority or CAN1 TX

  38.                 DCD     USB_LP_CAN1_RX0_IRQHandler ; USB Low  Priority or CAN1 RX0

  39.                 DCD     CAN1_RX1_IRQHandler        ; CAN1 RX1

  40.                 DCD     CAN1_SCE_IRQHandler        ; CAN1 SCE

  41.                 DCD     EXTI9_5_IRQHandler         ; EXTI Line 9..5

  42.                 DCD     TIM1_BRK_IRQHandler        ; TIM1 Break

  43.                 DCD     TIM1_UP_IRQHandler         ; TIM1 Update

  44.                 DCD     TIM1_TRG_COM_IRQHandler    ; TIM1 Trigger and Commutation

  45.                 DCD     TIM1_CC_IRQHandler         ; TIM1 Capture Compare

  46.                 DCD     TIM2_IRQHandler            ; TIM2

  47.                 DCD     TIM3_IRQHandler            ; TIM3

  48.                 DCD     TIM4_IRQHandler            ; TIM4

  49.                 DCD     I2C1_EV_IRQHandler         ; I2C1 Event

  50.                 DCD     I2C1_ER_IRQHandler         ; I2C1 Error

  51.                 DCD     I2C2_EV_IRQHandler         ; I2C2 Event

  52.                 DCD     I2C2_ER_IRQHandler         ; I2C2 Error

  53.                 DCD     SPI1_IRQHandler            ; SPI1

  54.                 DCD     SPI2_IRQHandler            ; SPI2

  55.                 DCD     USART1_IRQHandler          ; USART1

  56.                 DCD     USART2_IRQHandler          ; USART2

  57.                 DCD     USART3_IRQHandler          ; USART3

  58.                 DCD     EXTI15_10_IRQHandler       ; EXTI Line 15..10

  59.                 DCD     RTC_Alarm_IRQHandler        ; RTC Alarm through EXTI Line

  60.                 DCD     USBWakeUp_IRQHandler       ; USB Wakeup from suspend

  61. __Vectors_End
复制代码

可以看到第2~16行,为10个系统异常,剩下的43个全为外部中断。同时这里还定义了所有的中断处理函数名字,当外设产生中断时,则跳到中断向量表中对应中断处理函数位置,比如发生RTC中断事件,则跳到22行执行“RTC_IRQHandler()”函数内容。

STM32F103的异常和中断,基于Cortex-M3修改而来,前面的系统异常部分几乎没有变化,外部中断则对应不同的外设。

同样,STM32F103也继承了Cortex-M3的中断优先级规则,因为中断少了很多,中断优先级也用不了那么多,只使用了PRI_n的Bits[7:0]中的Bits[7:4]设置优先级,因此优先级分组为表 10.2.2 所示。

57~J4NE}UF)1~E~TTBX@H.png


表 10.2.2 STM32F103优先级分组

可见STM32F103系列最多有16级可编程优先级,STM32F103不使用PRIGROUP来命名分组,而采用NVIC_PRIORITYGROUP_x的方式命名,即NVIC_PRIORITYGROUP_0对应PRIGROUP为7,在“stm32f1xx_hal_cortex.h”有相关定义,如代码段 10.2.2 所示。

代码段 10.2.2 优先级分组定义(stm32f1xx_hal_cortex.h)

  1. /** @defgroup CORTEX_Preemption_Priority_Group CORTEX Preemption Priority Group

  2.   * @{

  3.   */

  4. #define NVIC_PRIORITYGROUP_0         0x00000007U /*!< 0 bits for pre-emption priority

  5.                                                       4 bits for subpriority */

  6. #define NVIC_PRIORITYGROUP_1         0x00000006U /*!< 1 bits for pre-emption priority

  7.                                                       3 bits for subpriority */

  8. #define NVIC_PRIORITYGROUP_2         0x00000005U /*!< 2 bits for pre-emption priority

  9.                                                       2 bits for subpriority */

  10. #define NVIC_PRIORITYGROUP_3         0x00000004U /*!< 3 bits for pre-emption priority

  11.                                                       1 bits for subpriority */

  12. #define NVIC_PRIORITYGROUP_4         0x00000003U /*!< 4 bits for pre-emption priority

  13.                                                       0 bits for subpriority */
复制代码

通常中断优先级分组只会设置一次,它针对的是系统中所有的中断。后续设置某个中断的中断优先级时,只需要在这个组规定的抢占优先级数和子优先级级数范围内分配优先级级数。后续代码中,不应该再修改中断优先级分组,否则导致中断顺序不按预期触发。本手册所有实验,将设置中断优先级分组放在了“HAL_Init()”里,如代码段 10.2.3 的第5行,调用“HAL_NVIC_SetPriorityGrouping()”函数设置中断优先级分组。

代码段 10.2.3设置中断优先级分组(stm32f1xx_hal.c)

  1. HAL_StatusTypeDef HAL_Init(void)



  2. {

  3. ……

  4.   /* Set Interrupt Group Priority */

  5.   HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);



  6.   /* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */

  7.   HAL_InitTick(TICK_INT_PRIORITY);

  8. ……

  9. }
复制代码

这里默认设置的优先级分组为NVIC_PRIORITYGROUP_4,则后续使用“HAL_NVIC_SetPriority()”函数设置优先级时,抢占优先级的范围是0~15,子优先级的值只能选择0。

“HAL_NVIC_SetPriority()”函数需要传入三个参数,参数IRQn是中断号,如表 10.2.1 所示的中断号。后两个是抢占优先级级数和子优先级级数,注意结合中断分组设置范围。

代码段 10.2.4 “HAL_NVIC_SetPriority()”函数原型(stm32f1xx_hal_cortex.c)

  1. /**

  2.   * @brief  Sets the priority of an interrupt.

  3.   * @param  IRQn: External interrupt number.

  4.   *         This parameter can be an enumerator of IRQn_Type enumeration

  5.   *         (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f10xx.h))

  6.   * @param  PreemptPriority: The preemption priority for the IRQn channel.

  7.   *         This parameter can be a value between 0 and 15

  8.   *         A lower priority value indicates a higher priority

  9.   * @param  SubPriority: the subpriority level for the IRQ channel.

  10.   *         This parameter can be a value between 0 and 15

  11.   *         A lower priority value indicates a higher priority.

  12.   * @retval None

  13.   */

  14. void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority)

  15. {

  16.   uint32_t prioritygroup = 0x00U;



  17.   /* Check the parameters */

  18.   assert_param(IS_NVIC_SUB_PRIORITY(SubPriority));

  19.   assert_param(IS_NVIC_PREEMPTION_PRIORITY(PreemptPriority));



  20.   prioritygroup = NVIC_GetPriorityGrouping();



  21.   NVIC_SetPriority(IRQn, NVIC_EncodePriority(prioritygroup, PreemptPriority, SubPriority));

  22. }
复制代码

【总结】

STM32中断重点理解中断优先级分组,然后根据中断优先级分组确定抢占优先级级数和子优先级级数。 体现在编程里,就是根据中断需求,先使用“HAL_NVIC_SetPriorityGrouping()”函数设置中断优先级分组,再使用“HAL_NVIC_SetPriority()”函数设置不同中断的抢占优先级级数和子优先级级数。

假设中断A的抢占优先级比中断B的抢占优先级高,两个中断同时发生,那么中断A优先执行。

假设中断A的抢占优先级和中断B的抢占优先级一样,两个中断同时发生,那么子优先级高的中断优先执行。

假设中断A的抢占优先级比中断B的抢占优先级高,中断B先发生,随后A也发生,那么将暂停中断B,先执行中断A,A执行完后,再回来执行中断B,最后执行主程序,这种效果即中断嵌套。

假设中断A的抢占优先级比中断B的抢占优先级一样,中断A的子优先级比中断B的子优先级高,中断B先发生,随后A也发生,那么中断A将等待中断B执行完后,才会执行中断A,即子优先级不能中断嵌套。

假设中断A的抢占优先级和中断B的抢占优先级一样,且子优先级也一样,两个中断同时发生,那么根据前面表 10.2.1 顺序,排在前面的先执行。

总结中断是否会优先执行依据:首先是抢占先式优先级等级,其次是子优先级等级,只有抢占优先级才可能出现中断嵌套。

作者:攻城狮子黄


收藏 评论0 发布时间:2022-8-30 18:22

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版