原创 Stm32中断优先级相关概念与使用笔记

2010-6-26 00:24 4117 10 10 分类: MCU/ 嵌入式

Stm32中断优先级相关概念与使用笔记<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


 


一、基本概念


1ARM cortex_m3内核支持256个中断(16个内核+240外部)和可编程256级中断优先级的设置,与中断控制和中断优先级控制相关的寄存器(NVICSYSTICK等)属于cortex_m3内核的部分。STM32采用了cortex_m3内核,所以这些部分仍旧保留使用,但并不是完全使用的,只是使用了一部分。


 


2STM32目前支持的中断共为84个(16个内核+68个外部),和16级可编程中断优先级的设置(仅使用中断优先级设置8bit中的高4位,见后面解释)。《参考最新101xx-107xx STM32 Reference manual, RM0008》。


 


以下主要对外部中断进行说明。


 


368个外部中断(通道)在STM32中已经固定的分配给相应的外部设备,每个中断通道都具备自己的中断优先级控制字节PRI_n8位,但在STM32中只有高4位有效),每4个通道的8位中断优先级控制字(PRI_n)构成一个32位的优先级寄存器(Priority Register)。68个通道的优先级寄存器至少有是1732位的寄存器,它们是NVIC寄存器的一部分。


 


4.这4bit的中断优先级控制位还要分成2组看,从高位开始,前面的定义抢先式优先级,后面为子优先级。4bit的组合可以有以下几种形式:


 





 分配情况


 


7


0:4


无抢先式优先级,16个子优先级


6


1:3


2个抢先式优先级,8个子优先级


5


2:2


4个抢先式优先级,4个子优先级


4


3:1


8个抢先式优先级,2个子优先级


<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />3/2/1/0


4:0


16个抢先式优先级,无子优先级


 


5.在一个系统中,通常只使用上面5种分配情况的一种,具体采用哪一种,需要在初始化时写入到一个32位寄存器AIRCApplication Interrupt and Reset Control Register)的第[108]3个位中。这3bit位有专门的称呼:PRIGROUP(具体写操作后面介绍)。比如你将0x05(上表的编号)写到AIRC[108]中,那么也就规定了你的系统中只有4个抢先式优先级,相同的抢先式优先级下还可以有4个不同级别的子优先级。


 


6AIRCPRIGROUP的值规定了设置和确定每个外部中断通道优先级的格式。例如,在上面将0x05写入了AIRCPRIGROUP,也就规定了当前系统中只能有4个抢先式优先级,相同的抢先式优先级下还可以有4个不同级别的子优先级,他们分别为:




[76]


 


[54]


 


[30]


00


0号抢先优先级


00


0号子优先级


无效


01


1号抢先优先级


01


1号子优先级


无效


10


2号抢先优先级


10


2号子优先级


无效


11


3号抢先优先级


11


3号子优先级


无效


7.如果在你的系统中使用了TIME2(中断通道28)和EXTI0(中断通道6)两个中断,而TIME2中断必须优先响应,而且当系统在执行EXIT0中断服务时也必须打断(抢先、嵌套),就必须设置TIME2的抢先优先级比EXTI0的抢先优先级要高(数目小)。假定EXTI02号抢先优先级,那么TIME2就必须设置成01号抢先优先级。这些工作需要在AIRCPRIGROUP后进行设置。


 


8.具体优先级的确定和嵌套规则。ARM cortex_m3STM32)规定


a/ 只能高抢先优先级的中断可以打断低抢先优先级的中断服务,构成中断嵌套。


b/ 2n)个相同抢先优先级的中断出现,它们之间不能构成中断嵌套,但STM32首先响应子优先级高的中断。


c/ 2n)个相同抢先优先级和相同子优先级的中断出现,STM32首先响应在该中断通道向量地址低的中断(ROM0008,表52)。


具体一点:


0号抢先优先级的中断,可以打断任何中断抢先优先级为非0号的中断;1号抢先优先级的中断,可以打断任何中断抢先优先级为234号的中断;…..构成中断嵌套。


如果两个中断的抢先优先级相同,谁先出现,就先响应谁,不构成嵌套。如果一起出现(或挂在那里等待),就看它们2个谁的子优先级高了,如果子优先级也相同,就看它们的中断向量位置了。


 


9.上电RESET后,AIRCPRIGROUP[108],因此此时系统使用16个抢先优先级,无子优先级。另外由于所有外部中断通道的优先级控制字PRI_n也都是0,所以根据上面的定义可以得出,此时68个外部中断通道的抢先优先级都是0号,没有子优先级的区分。故此时不会发生任何的中断嵌套行为,谁也不能打断当前正在执行的中断服务。当多个中断出现后,则看它们的中断向量地址:地址越低,中断级别越高,STM32优先响应。注意:此时内部中断的抢先优先级也都是0号,由于它们的中断向量地址比外部中断向量地址都低,所以它们的优先级比外部中断高,但如果此时正在执行一个外部中断服务,它们也必须排队等待,只是可以插队,当正在执行的中断完成后,它们可以优先得到执行。


 


 


了解以上基本概念还是不够的,还要了解具体中断的控制有那些途径,中断服务程序如何正确的编写。下面的描述主要以TIME2通道为例。


 


二、中断控制


1.对于STM32讲,外部中断通道位置2835号优先级)是给外部设备TIME2的,但TIME2本身能够引起中断的中断源或事件有好多个,比如更新事件(上溢/下溢)、输入捕获、输出匹配、DMA申请等。


(题外话:就一个通用定时计数器,比8位控制器中TIME要复杂多了。学过AVR的,可能对输入捕获、输出匹配等还有概念,如果你学的标准架构的MCS-51,那么上手32位控制困难就更多了。所以我一直推荐学习8位应该认真从AVR开始,尽管51有很大的市场,价格也相对便宜些,但从发展的眼光,从后续掌握32位的使用,AVR是比较好的选择。)


 


   所有TIME2的中断事件都是通过一个TIME2的中断通道向STM32内核提出申请的,那么STM32中如何处理和控制TIME2和它众多的、不同的、中断申请呢?


 


2cortex_m3内核对于每一个外部中断通道都有相应的控制字和控制位,用于单独的和总的控制该中断通道。它们包括有:


中断优先级控制字:PRI_n(上面提到的)


中断允许设置位:ISER寄存器中


中断允许清除位:在ICER寄存器中


中断悬挂Pending(排队等待)位置位:在ISPR寄存器中(类似于置中断通道标志位)


中断悬挂Pending(排队等待)位清除:在ICPR寄存器中(用于清除中断通道标志位)


正在被服务的中断(Active)标志位:在IABR寄存器中,(只读,可以知道当前内核正在处理哪个中断通道)


 


因此,与TIME2中断通道相关的,在NVIC中有13bits,它们是PRI_288 bits(只用高4);中断通道允许,中断通道清除(相当禁止),中断通道Pending置位(我的理解是中断请求发生了,但当前有其它中断服务在执行,你的中断级别又不能打断别人,所以Pending等待,这个应该由硬件置位的),中断Pending位清除(可以通过软件将本次中断请求且尚处在Pending状态,取消掉),正在被服务的中断(Active)标志位,各1bit


 


上面的控制字和控制位都是在NVIC中的寄存器组中,可惜的是在STM32中竟然不给出任何的解释和说明。


 


3.作为外围设备TIME2本身也包括更具体的,管理自己不同中断的中断控制器(位),它们主要是各个不同类型中断的允许控制位,和各自相应中断标志位。(这个STM32的手册中有详细的说明了)


 


4.在弄清楚23两点的基础上,我们可以看看TIME2的中断过程,以及如何控制的了。


 


a/ 初始化过程


设置AIRCPRIGROUP的值,规定系统中的抢先优先级和子优先级的个数(在4bits中占用的位数)


设置TIME2本身的寄存器,允许相应的中断,如允许UIETIME2_DIER的第[0]位)


设置TIME2中断通道的抢先优先级和子优先级(PRI_28,在NVIC寄存器组中)


设置允许TIME2中断通道。NVIC寄存器组的ISER寄存器中的一位。


 


b/ 中断响应过程


TIME2UIE条件成立(更新,上溢或下溢),硬件将TIME2本身寄存器中UIE中断标志置位,然后通过TIME2中断通道向内核申请中断。


此时硬件将TIME2Pending标志置位,相当于中断通道标志置位,表示TIME2有中断申请。


如果当前有中断在处理,TIME2的中断级别不高,那么就保持Pending,当然软件可以通过写ICPR寄存器中相应的位把本次中断清除掉。


当内核有空,开始响应TIME2的中断,进入TIME2的中断服务。此时硬件将IABR寄存器中相应的标志位置位,表示TIME2中断正在被处理。同时硬件清除TIME2Pending标志位。


 


c/ 执行TIME2的中断服务程序


所有TIME2的中断事件,都是在一个TIME2中断服务程序中完成的,所以进入中断程序后,中断程序需要首先判断是哪个TIME2的具体事件的中断,然后转移到相应的服务代码段去。


注意不要忘了把该具体中断事件的中断标志位清除掉,硬件是不会自动清除TIME2寄存器中具体的中断标志位的。


 


d/ 中断返回


执行完中断服务后,中断返回过程,在这个过程中需要:


硬件将IABR寄存器中相应的标志位清零,表示该中断处理完成


如果TIME2本身还有中断标志位置位,表示TIME2 还有中断在申请,则重新将TIME2Pending标志置为1,等待再次进入TIME2的中断服务。


 


注意:以上中断过程在《ARM Cortex-M3权威指南》中有详细描述,并配合时序图说明,可以参考。


 


如果以上明白了,那么可以在ST提供的函数库的帮助下,正确的设置和使用STM32的中断系统了。


 


如果你要了解更深入的东西,或者直接对寄存器操作,还要继续望下看。


 


三、深入NVIC


 


1. 看看Cortex-M3中定义与NVIC相关的寄存器有那些


SysTick     Control and Status Register         Read/write          0xE000E010


SysTick     Reload Value Register               Read/write         0xE000E014


SysTick     Current Value Register              Read/write clear    0xE000E018


SysTick     Calibration Value Register          Read-only           0xE000E01C


 


Irq 0 to 31     Set Enable Register             Read/write          0xE000E100


. . . . .


Irq 224 to 239  Set Enable Register             Read/write          0xE000E11C


 


Irq 0 to 31     Clear Enable Register           Read/write          0xE000E180


. . . . .


Irq 224 to 239 Clear Enable Register           Read/write          0xE000E19C


 


Irq 0 to 31     Set Pending Register            Read/write          0xE000E200


. . . . .


Irq 224 to 239  Set Pending Register            Read/write          0xE000E21C


 


Irq 0 to 31     Clear Pending Register          Read/write          0xE000E280


. . . . .


Irq 224 to 239  Clear Pending Register          Read/write          0xE000E29C


 


 


Irq 0 to 31     Active Bit Register             Read-only           0xE000E300


. . . . . .


Irq 224 to 239  Active Bit Register             Read-only           0xE000E31C


 


Irq 0 to 3      Priority Register               Read/write          0xE000E400


. . . . .


Irq 224 to 239  Priority Register               Read/write          0xE000E4EC


 


CPUID Base Register                             Read-only           0xE000ED00


Interrupt ControlState Register        Read/write or read-only     0xE000ED04


Vector Table Offset Register                    Read/write          0xE000ED08


Application Interrupt/Reset Control Register    Read/write          0xE000ED0C


System Control Register                         Read/write          0xE000ED10


Configuration Control Register                  Read/write          0xE000ED14


System Handlers 4-7 Priority Register           Read/write          0xE000ED18


System Handlers 8-11 Priority Register          Read/write          0xE000ED1C


System Handlers 12-15 Priority Register         Read/write          0xE000ED20


. . . . .


 


2Stm32中用了那些


 


下面是从ST公司提供的函数库的头文件得到的,库是v3.1.0


/* memory mapping struct for Nested Vectored Interrupt Controller (NVIC) */


typedef struct


{


  __IO uint32_t ISER[8];                 /*!< Interrupt Set Enable Register            */


       uint32_t RESERVED0[24];


  __IO uint32_t ICER[8];                 /*!< Interrupt Clear Enable Register          */


       uint32_t RSERVED1[24];


  __IO uint32_t ISPR[8];                 /*!< Interrupt Set Pending Register           */


       uint32_t RESERVED2[24];


  __IO uint32_t ICPR[8];                 /*!< Interrupt Clear Pending Register         */


       uint32_t RESERVED3[24];


  __IO uint32_t IABR[8];                 /*!< Interrupt Active bit Register            */


       uint32_t RESERVED4[56];


  __IO uint8_t  IP[240];                 /*!< Interrupt Priority Register, 8Bit wide   */


       uint32_t RESERVED5[644];


  __O  uint32_t STIR;                   /*!< Software Trigger Interrupt Register      */


}  NVIC_Type;


 


a/  寄存器ISERICERISPRICPRIABRSTM32中都使用的8个(实际3个就够了,后面的将来还要扩充?)。这些32位的寄存器中每一位对应了一个中断通道相应的标志。


比如地址在0xE000E100ISER[0]这个32位的寄存器,第0位是中断通道0的允许位,第2位是中断通道1的允许标志……32位是中断通道31的允许位;接下来地址在0xE000E104ISER[1]则是中断通道32-63的允许位。ICERISPRICPRIABR的结构相同,只是含义不同。


 


注意是对这些寄存器的操作:写1表示置位或清除,写0无任何影响。


 


例如:


0xE000E100ISER[0]的第0位写1,表示允许中断通道0中断;


但对0xE000E100ISER[0]的第0位写0,则没有任何作用,该位保持不变。


如果要禁止中断通道0的中断响应,那么就必须:


0xE000E180ICER[0]的第0位写1,表示禁止中断通道0的中断;


0xE000E180ICER[0]的第0位写0,也是不起任何作用的。


 


b/ IP[240]用于定义240个外部中断通道的优先级,每1个字节对应一个通道。4个通道的IP[]构成一个32位的寄存器。在STM32中最多有68个外部中断通道,每个IP[]1个字节中只使用高4位(见前面介绍)。IP[]的结构如下:


 


 




 


31:28


27:24


23:20


19:16


15:12


11:8


7:4


3:0


 


E000E400


PIR_3


PIR_2


PIR_1


PIR_0


8位的高4位有效,灰色位表示无效


E000E404


PIR_7


PIR_6


PIR_5


PIR_4


……


……


……


……


……


 


c/ ST公司提供的函数库的头文件中另一个数据结构中,还有一个寄存器需要关注


 


/* memory mapping struct for System Control Block */


typedef struct


{


__I uint32_t CPUID;     /*!<CPU ID Base Register */


__IO uint32_t ICSR;     /*!< Interrupt Control State Register */


__IO uint32_t VTOR;     /*!< Vector Table Offset Register  */


__IO uint32_t AIRCR;    /*!< Application Interrupt / Reset Control Register  */


__IO uint32_t SCR;      /*!< System Control Register */


__IO uint32_t CCR;      /*!< Configuration Control Register */


__IO uint8_t  SHP[12];  /*!< System Handlers Priority Registers (4-7, 8-11, 12-15)*/


__IO uint32_t SHCSR;    /*!< System Handler Control and State Register */


__IO uint32_t CFSR;     /*!< Configurable Fault Status Register */


__IO uint32_t HFSR;     /*!< Hard Fault Status Register */


__IO uint32_t DFSR;     /*!< Debug Fault Status Register */


__IO uint32_t MMFAR;    /*!< Mem Manage Address Register */


__IO uint32_t BFAR;     /*!< Bus Fault Address Register  */


__IO uint32_t AFSR;     /*!< Auxiliary Fault Status Register */


__I  uint32_t PFR[2];   /*!< Processor Feature Register  */


__I  uint32_t DFR;      /*!< Debug Feature Register */


__I  uint32_t ADR;      /*!< Auxiliary Feature Register */


__I  uint32_t MMFR[4];  /*!< Memory Model Feature Register */


__I  uint32_t ISAR[5];  /*!< ISA Feature Register */


} SCB_Type;


 


它就是地址在0xE000ED0C32位寄存器AIRCRApplication Interrupt/Reset Control Register),该寄存器的[10:8]3位就是 PRIGROUP的定义位值,它规定了系统中有多少个抢先级中断和子优先级中断。而STM32只使用高4bits,起可能的值如下(来自ST的函数库头文件中的定义)


 


#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 */


 


由于这个寄存器相当重要,所以为了防止误操作(写),因此要改写这个寄存器的内容时,必须同时向这个寄存器的高16[3116]写验证字(Register key 0x05FA


 


例如:SBC->AIRCR |= 0x05FA0000 || 0x300;    // 设置系统中断有16个抢先优先// 级,无子优先级


 


 


d/ 下面的定义与SYSTICK相关,有时也会用到的。


/* memory mapping struct for SysTick */


typedef struct


{


  __IO uint32_t CTRL;       /*!< SysTick Control and Status Register */


  __IO uint32_t LOAD;       /*!< SysTick Reload Value Register       */


  __IO uint32_t VAL;        /*!< SysTick Current Value Register      */


  __I  uint32_t CALIB;      /*!< SysTick Calibration Register        */


} SysTick_Type;



PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
我要评论
0
10
关闭 站长推荐上一条 /3 下一条