轉自
1. Cortex-M3的異常/中斷屏蔽寄存器組
注:只有在特權級下,才允許訪問這3個寄存器。
名 字 |
功能描述 |
PRIMASK |
只有單一比特的寄存器。置為1后,就關掉所有可屏蔽異常,只剩下NMI和硬Fault可以響應。默認值是0,表示沒有關閉中斷。 |
FAULTMASK |
只有單一比特的寄存器。置為1后,只有NMI可以響應。默認值為0,表示沒有關異常。 |
BASEPRI |
該寄存器最多有9位(由表達優先級的位數決定)。定義了被屏蔽優先級的閾值。當它被設置為某個值后,所有優先級號大於等於此值的中斷都被關。若設置成0,則不關斷任何中斷,0為默認值。 |
注:寄存器BASEPRI的有效位數受系統中表達優先級的位數影響,如果系統中只使用3個位來表達優先級,則BASEPRI有意義的值僅為0x00、0x20、0x40、0x60、0x80、0xA0、0xC0和0xE0
使用MRS/MSR指令訪問這三個寄存器,比如:
MRS R0, BASEPRI ;讀取BASEPRI到R0中
MSR BASEPRI, R0 ;將R0數據寫入到BASEPRI中
為了快速的開關中斷,CM3還專門設置了一條CPS指令,有四種用法:
CPSID I ;PRIMASK=1,關中斷
CPSIE I ;PRIMASK=0,開中斷
CPSID F ;FAULTMASK=1,關異常
CPSIE F ;FAULTMASK=0,開異常
CMSIS-M3微控制器軟件接口標准中的core_cm3.h給出了開關中斷或異常的函數:
1.1 開/關中斷
1: /**
2: * @brief Set the Priority Mask value
3: *
4: * @param priMask PriMask
5: *
6: * Set the priority mask bit in the priority mask register
7: */
8: static __INLINE void __set_PRIMASK(uint32_t priMask)
9: {
10: register uint32_t __regPriMask __ASM("primask");
11: __regPriMask = (priMask);
12: }
使用__set_PRIMASK(1)關閉中斷;__setPRIMASK(0)開啟中斷。
一些說明:__INLINE是宏定義,對應__inline,這是keil編譯器自定義關鍵字,表示這個函數是內聯函數,但並不是強制性內聯,編譯器最終決定是否內聯。
__ASM(“primask”): __ASM也是一個宏,對應__asm,這是keil編譯器自定義關鍵字,關於這個關鍵字,有相當多的用法,可以在C中內嵌匯編語言、內嵌匯編函數、指定匯編標號以及本代碼中的聲明一個已命名寄存器變量。這里,已命名的寄存器是("primask"),也就是說寄存器變量__regPriMask等同於編譯器已命名的primask。語法為:
register type var-name __asm(reg);
keil編譯器已命名的寄存器變量為:
寄存器 |
__asm修飾的字符串 |
處理器 |
|
" |
All processors |
|
|
All processors |
|
|
Cortex-M3, Cortex-M4 |
|
|
Cortex-M3, Cortex-M4 |
|
|
Cortex-M0, Cortex-M1, Cortex-M3, Cortex-M4 |
|
|
Cortex-M0, Cortex-M1, Cortex-M3, Cortex-M4 |
|
|
Cortex-M0, Cortex-M1, Cortex-M3, Cortex-M4 |
|
|
Cortex-M0, Cortex-M1, Cortex-M3, Cortex-M4 |
|
|
Cortex-M3, Cortex-M4 |
|
|
Cortex-M0, Cortex-M1, Cortex-M3, Cortex-M4 |
|
|
Cortex-M0, Cortex-M1, Cortex-M3, Cortex-M4 |
|
|
Cortex-M0, Cortex-M1, Cortex-M3, Cortex-M4 |
|
|
Cortex-M0, Cortex-M1, Cortex-M3, Cortex-M4 |
|
|
Cortex-M0, Cortex-M1, Cortex-M3, Cortex-M4 |
|
|
Cortex-M0, Cortex-M1, Cortex-M3, Cortex-M4 |
|
|
Cortex-M0, Cortex-M1, Cortex-M3, Cortex-M4 |
|
|
All processors |
|
|
All processors |
|
"r13" or "sp" |
All processors |
|
"r15" or "pc" |
All processors |
|
|
All processors, apart from Cortex-M series processors. |
|
|
Cortex-M0, Cortex-M1, Cortex-M3, Cortex-M4 |
1.2 開/關異常
1: /**
2: * @brief Set the Fault Mask value
3: *
4: * @param faultMask faultMask value
5: *
6: * Set the fault mask register
7: */
8: static __INLINE void __set_FAULTMASK(uint32_t faultMask)
9: {
10: register uint32_t __regFaultMask __ASM("faultmask");
11: __regFaultMask = (faultMask & 1);
12: }
使用__set_FAULTMASK(1)來關閉中斷和異常;使用__set_FAULTMASK(0)開啟中斷和異常.
1.3 更精確的優先級屏蔽
1: /**
2: * @brief Set the Base Priority value
3: *
4: * @param basePri BasePriority
5: *
6: * Set the base priority register
7: */
8: static __INLINE void __set_BASEPRI(uint32_t basePri)
9: {
10: register uint32_t __regBasePri __ASM("basepri");
11: __regBasePri = (basePri & 0xff);
12: }
比如想屏蔽優先級不高於0x60的中斷,則使用代碼:__set_BASEPRI(0x60);如果想取消中斷屏蔽,則使用__set_BASEPRI(0)即可。
2.異常/中斷和優先級
Cortex-M3的異常包括系統異常和外設中斷,系統異常是Cortex-M3內核自帶的一些異常,比如復位、總線Fault和SysTick等等(見表2-1),外設中斷是指制造CPU的廠家加入的,比如串口、定時器中斷等等(見表2-2)。
注:關於異常和中斷,想要分個清清楚楚實在有點困難。異常和中斷都可以“中斷”正常執行的代碼流,區別在於,異常是Cortex-M3內核產生的“中斷”信號,而中斷是Cortex-M3內核外部(片上外設或外部中斷信號)產生的“中斷”信號。希望你看懂了,有時候你心里明白,但要講的清清楚楚着實難!
表2-1:系統異常
編號 |
類型 |
優先級 |
簡介 |
0 |
N/A |
N/A |
無 |
1 |
復位 |
-3(最高) |
復位 |
2 |
NMI |
-2 |
不可屏蔽中斷(來自外部NMI輸入腳) |
3 |
硬Fault |
-1 |
只要FAULTMASK沒有置位,硬Fault服務例程會被強制執行 |
4 |
存儲器管理Fault |
可編程 |
MPU訪問違例以及訪問非法位置均可引發。企圖在“非執行區”取址也會引發此Fault。 |
5 |
總線Fault |
可編程 |
總線收到了錯誤響應,原因可以使預取流產或數據流產,企圖訪問協處理器也會引發此Fault |
6 |
用法Fault |
可編程 |
由於程序錯誤導致的異常。通常是使用了一條無效指令,或者是非法的狀態轉換,例如嘗試切換到ARM狀態 |
7~10 |
保留 |
保留 |
保留 |
11 |
SVCall |
可編程 |
執行系統服務調用指令(SVC)引發的異常 |
12 |
調試監視器 |
可編程 |
調試器(斷點、數據觀察點,或者是外部調試請求) |
13 |
保留 |
保留 |
保留 |
14 |
PendSV |
可編程 |
為系統設備而設的“可掛起請求” |
15 |
SysTick |
可編程 |
系統節拍時鍾定時器(SysTick) |
表2-2:外設中斷
編號 | 類型 | 優先級 | 簡介 |
16 | IRQ #0 |
可編程 |
外設中斷#0 |
17 | IRQ #1 |
可編程 |
外設中斷#1 |
... | ... |
可編程 |
... |
255 | IRQ #239 |
可編程 |
外設中斷#239 |
注:表2-1和2-2中的“編號”有着特殊的意義,一是特殊功能寄存器IPSR中會記錄當前正在服務的異常並給出了它的編號;二是優先級完全相同的多個異常同時掛起時,則先響應異常編號最小的那一個。
一個發生的異常如果不能被立即響應,就稱它被“掛起”,值得一提的是,對於被掛起的中斷/異常,中斷/異常信號不必由其產生者保持,NVIC的掛起狀態寄存器會來保持這個信號。所以哪怕后來掛起的中斷源釋放了中斷請求信號,曾經的中斷請求也不會丟失。
除了復位、NMI和硬Fault三個異常具有固定的優先級外,其它所有異常和中斷的優先級都是可以編程的。這就涉及到優先級配置寄存器。Cortex-M3優先級配置寄存器共8位,所以可以有256級的可編程優先級。但是大多數Cortex-M3芯片都會精簡設計。
LPC177x/8x使用了優先級配置寄存器的5位,所以有32級可編程優先級。復位后,對於所有優先級可編程的異常,其優先級都被初始化為0(最高優先級)
2.1 設置異常/中斷的優先級
2.1.1 系統異常優先級設置
SHPR1-SHPR3寄存器用於設置有可編程優先級的系統異常,可設置的優先級為0到31。SHPR1-SHPR3可按字節訪問。為了提高軟件效率,CMSIS簡化了SCB寄存器的表述。在CMSIS中,字節數組SHP[0] 到SHP[12]對應於寄存器SHPR1至SHPR3。
表2-3:SHPR1寄存器的位分配
位 | 名稱 |
功能 |
[31:24] |
PRI_7 |
保留 |
[23:16] |
PRI_6 |
系統處理程序6的優先級,用法Fault |
[15:8] |
PRI_5 |
系統處理程序5的優先級,總線Fault |
[7:0] |
PRI_4 |
系統處理程序4的優先級,存儲器管理Fault |
表2-3:SHPR2寄存器的位分配
位 |
名稱 |
功能 |
[31:24] |
PRI_11 |
系統處理程序11的優先級,SVCall |
[23:0] |
- |
保留 |
表2-4:SHPR3寄存器的位分配
位 |
名稱 |
功能 |
[31:24] |
PRI_15 |
系統處理程序15的優先級,SysTick 異常 |
[23:16] |
PRI_14 |
系統處理程序14的優先級,PendSV |
[15:0] |
- |
保留 |
注:每個PRI_N域為8位寬,但是處理器僅實現每個域的位[7:3],位[2:0]讀取值為零並忽略寫入值。