轉自:http://www.21ic.com/embed/jiaocheng/sheji/201209/5634.htmlhtml
STM32(Cortex-M3)中有兩個優先級的概念:搶佔式優先級和響應優先級,也把響應優先級稱做「亞優先級」或「副優先級」,每一箇中斷源都須要被指定這兩種優先級。函數
高佔先式優先級的中斷事件會打斷當前的主程序/中斷程序運行—搶斷式優先響應,俗稱中斷嵌套。spa
首先是佔先式優先級,其次是副優先級;code
佔先式優先級決定是否會有中斷嵌套;htm
Reset、NMI、Hard Fault 優先級爲負(高於普通中斷優先級)且不可調整。blog
具備高搶佔式優先級的中斷能夠在具備低搶佔式優先級的中斷處理過程當中被響應,即中斷的嵌套,或者說高搶佔式優先級的中斷能夠嵌套低搶佔式優先級的中斷。事件
當兩個中斷源的搶佔式優先級相同時,這兩個中斷將沒有嵌套關係,當一箇中斷到來後,若是正在處理另外一箇中斷,這個後到來的中斷就要等到前一箇中斷處理完以後才能被處理。若是這兩個中斷同時到達,則中斷控制器根據他們的響應優先級高低來決定先處理哪個;若是他們的搶佔式優先級和響應優先級都相等,則根據他們在中斷表中的排位順序決定先處理哪個。get
既然每一箇中斷源都須要被指定這兩種優先級,就須要有相應的寄存器位記錄每一箇中斷的優先級;在Cortex-M3中定義了8個比特位用於設置中斷源的優先級,這8個比特位能夠有8種分配方式,以下:it
全部8位用於指定響應優先級io
這就是優先級分組的概念。
Cortex-M3容許具備較少中斷源時使用較少的寄存器位指定中斷源的優先級,所以STM32把指定中斷優先級的寄存器位減小到4位,這4個寄存器位的分組方式以下:
AIRC(Application Interrupt and Reset Register)寄存器中有用於指定優先級的 4 bits。這4個bits用於分配preemption優先級和sub優先級,在STM32的固件庫中定義以下:
/* Preemption Priority Group */ #define NVIC_PriorityGroup_0 ((u32)0x700) /* 0 bits for pre-emption priority 4 bits for subpriority */ #define NVIC_PriorityGroup_1 ((u32)0x600) /* 1 bits for pre-emption priority 3 bits for subpriority */ #define NVIC_PriorityGroup_2 ((u32)0x500) /* 2 bits for pre-emption priority 2 bits for subpriority */ #define NVIC_PriorityGroup_3 ((u32)0x400) /* 3 bits for pre-emption priority 1 bits for subpriority */ #define NVIC_PriorityGroup_4 ((u32)0x300) /* 4 bits for pre-emption priority 0 bits for subpriority */
能夠經過調用STM32的固件庫中的函數NVIC_PriorityGroupConfig()選擇使用哪一種優先級分組方式,這個函數的參數有下列5種:
接下來就是指定中斷源的優先級,下面以一個簡單的例子說明如何指定中斷源的搶佔式優先級和響應優先級:
// 選擇使用優先級分組第1組 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); // 使能EXTI0中斷 NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQChannel; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 指定搶佔式優先級別1 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 指定響應優先級別0 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); // 使能EXTI9_5中斷 NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 指定搶佔式優先級別0 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 指定響應優先級別1 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);
--------------------------------------------------------------------------------
要注意的幾點是:
1. 若是指定的搶佔式優先級別或響應優先級別超出了選定的優先級分組所限定的範圍,將可能獲得意想不到的結果;
2. 搶佔式優先級別相同的中斷源之間沒有嵌套關係;
3. 若是某個中斷源被指定爲某個搶佔式優先級別,又沒有其它中斷源處於同一個搶佔式優先級別,則能夠爲這個中斷源指定任意有效的響應優先級別。
在STM32/Cortex-M3中是經過改變CPU的當前優先級來容許或禁止中斷。
PRIMASK位:只容許NMI和hard fault異常,其餘中斷/異常都被屏蔽(當前CPU優先級=0)。
FAULTMASK位:只容許NMI,其餘全部中斷/異常都被屏蔽(當前CPU優先級=-1)。
在STM32固件庫中(stm32f10x_nvic.c和stm32f10x_nvic.h) 定義了四個函數操做PRIMASK位和FAULTMASK位,改變CPU的當前優先級,從而達到控制全部中斷的目的。
void NVIC_SETPRIMASK(void); void NVIC_SETFAULTMASK(void);
void NVIC_SETPRIMASK(void); void NVIC_SETFAULTMASK(void);
上面兩組函數要成對使用,但不能交叉使用。
例如:
NVIC_SETPRIMASK(); //關閉總中斷 NVIC_RESETPRIMASK();//開放總中斷
NVIC_SETFAULTMASK(); //關閉總中斷 NVIC_RESETFAULTMASK();//開放總中斷
NVIC_SETPRIMASK(); // Disable Interrupts NVIC_RESETPRIMASK(); // Enable Interrupts
-------------------------------------------------------------------------------------------------
補充:
#define CLI() __set_PRIMASK(1) #define SEI() __set_PRIMASK(0)
來實現開關總中斷的功能。